Jump to content

Forms of Encapsulation


Recommended Posts

First I would like to say I have searched forums and read the documentation (ok I skimmed it...). While I have found a post similar to this one back in 2005, I wanted to address this issue again.

My Question: What forms of encapsulation does AutoItv3 provide.

List of Forms (that I know exist):

  • Block
  • Function [yes]
  • Class
  • Nested Class
  • Package

I have heard someone refer to a Class as a "chunk" in AutoItv3. I have never heard of this... but the example used scope resolution operators such as "::".

List of forms explained:

Block

A variable declared inside the block can not be seen from outside the block. If the variable needs to be reused, declare it before the block.

Example:

for(i = 0;i<10;i++) {
  String foo new String(foo != String ? ord(i) : foo + ord(i));
  System.println(foo);
}
try {
  System.println(foo); // foo can not be seen.. exception occurs
}

Function

function foo(bar, baz) { //checks that bar and baz are real. pointless function
  return baz != NULL && bar != NULL;
}

Class & Interfaces

A class is a collection of fields and functions. Some languages support operators such as final, abstract, static, public, constant, protected, private, synchronized.

Modifiers can be used on the class itself,

An example in poetic PHP:

<?php
interface DataBaseReflection {
  
  /**
   * Sets the primary key for the database related instance.
   * 
   * @param (int) $identity
   * @throws InvalidArgumentException if $identity is not an unsigned integer.
   * @return (int) $identity
   */
  public function setIdentity($identity);
  
  /**
   * Returns the primary key for the instance which invokes this method
   * as it relates to that instance's corresponding table.
   * 
   * @throws NoIdentitySetException if there is no Identity set.
   * @return (int) number
   */
  public function getIdentity();
  
}

?>
<?php

/**
 * DataBaseReflection manages the identities of objects in the application layer
 * in relation to the object's table identity (a unsigned INT auto_increment primary key).
 * If the table already has a primary key and does not use an unsigned integer, 
 * implement ADataBaseReflection instead of extending this class.
 * 
 * @package new2net.standard
 */
abstract class DataBaseUnsignedReflection implements DataBaseReflection {
  /**
   * The table's primary key (unsigned int).
   * @var (int)
   */
  protected $identity;

  public final function setIdentity($identity) {
    if(is_numeric($identity) && $identity > 0) {
      $this->identity = $identity;
      return $this->identity;
    } else {
      throw new InvalidArgumentException();
    }
  }
  
  public final function getIdentity() {
    if(is_int($this->identity) && $this->identity > 0) {
      return (int) $this->identity;  
    } else {
      throw new NoIdentitySetException();
    }
  }
    
}
?><?php

/**
 * Creating a User instance will force the end-user to log in using new2net's
 * CAS (central authentication system). Creating this instance will also attempt
 * to authorize the user with the database.
 *
 * @author new2net
 * @package net.phantomcircuit.standard
 */
class User extends DataBaseUnsignedReflection {
  //private parent::$identity  ~~  User_ID ~~ unsigned Int

  /**
   * The username that my central authentication system returns; if this is empty or
   * null then the user has not been authenticated yet.
   * @var (string)
   */
  private $username;
  
  /**
   * The user's first name.
   * @var (string)
   */
  private $firstName;
  
  /**
   * The user's last name.
   * @var (string)
   */
  private $lastName;
  
  
  /**
   * The user's email.
   * @var (string)
   */
  private $email;

  /**
   * Roles is a combination of the valid user roles
   * See the User class for more information.
   * @var (int)
   */
  private $roles;

  /**
   * True is the session has started, otherwise false.
   * @var (bool)
   */
  private static $session = FALSE;

  const ROLE_APPLICANT    = 1; // User.roles is a bitmask  [--- or `SET()` in MySQL ---] .. 
  const ROLE_REVIEWER     = 2; // its just a 64bit integer really, nothing but 64 potential flags
  const ROLE_INTERVIEWER  = 4;
  const ROLE_MANAGER      = 8;
  
  public function __construct() {
    
    if(!self::$session) self::session_begin();
    
    DATABASE::connect();
    $this->username = $this->authenticate();
    $this->authorize();
    
  }

  final private function authenticate() {
    // sorry, don't want to share my CAS code. :) it sets $this->username when successful, otherwise redirects them to login w/ the CAS.
  }

  final private function authorize() {
    if (DEBUG::SANITY) DEBUG::SANITY(sprintf("Attempting to authorize %s.",$this->username));
    $query = sprintf("SELECT User_ID, roles+0 as roles, first_name, last_name, email
                      FROM `User`
                      WHERE username = '%s';", mysql_real_escape_string(($this->getUserName())));
    if(mysql_errno()) DATABASE::mysqlDebug();
    
    $res = mysql_query($query);
    if (mysql_num_rows($res)) {
      $row = mysql_fetch_assoc($res);
      $this->setIdentity((int) $row['User_ID']);
      $this->roles     = $row['roles'];
      $this->firstName = $row['first_name'];
      $this->lastName  = $row['last_name'];
      $this->email     = $row['email'];
      return true;
    } else {
      throw new NoSuchUserException();
    }
  }

  /**
   * You can check a user against the User::ROLE_* constants, 
   * you may also combine them using bitwise operators to check for multiple roles.
   * 
   * @param (unsigned int) $role
   * @return (boolean) TRUE if they have the role, otherwise FALSE.
   */
  public final function hasRole($role) {
    return (bool) ($this->roles & $role); //the parenthesis here are important
  }
  
  /**
   * Sends all roles and the user's corresponding roles to STDOUT.
   * return (void)
   */
  public final function dumpRoles() {
    echo "<pre>", 
    "Applicant....: ", (self::ROLE_APPLICANT   & $this->roles ? "Yes" : "No") . "\n",
    "Reviewer.....: ", (self::ROLE_REVIEWER    & $this->roles ? "Yes" : "No") . "\n",
    "Interviewer..: ", (self::ROLE_INTERVIEWER & $this->roles ? "Yes" : "No") . "\n",
    "Manager......: ", (self::ROLE_MANAGER     & $this->roles ? "Yes" : "No") . "\n",
    "</pre>";
  }

  /**
   * Starts the session with the configuration specified in the CONFIG class.
   * @return (bool) True if the session started, otherwise false.
   */
  public static final function session_begin() {
    if(!self::$session) {
      session_save_path(CONFIG::SESSION_SAVE_PATH);
      ini_set('session.name',            CONFIG::SESSION_NAME);
      ini_set('session.gc_probability',  CONFIG::SESSION_GC_PROBABILITY);
      ini_set('session.gc_maxlifetime',  CONFIG::SESSION_GC_MAX_LIFETIME);
      ini_set('session.cookie_lifetime', CONFIG::SESSION_COOKIE_LIFETIME);
      ini_set('session.cache_expire',    CONFIG::SESSION_CACHE_EXPIRE);
    }
    self::$session = session_start();
    if (DEBUG::SANITY) DEBUG::SANITY(self::$session ? "Session has started." : "Session failed to start!");
    return (bool) self::$session;
  }

  /**
   * Returns the user's username.
   * @return (string)
   */
  public final function getUserName() {
    return (string) $this->username;
  }
  
  /**
   * Returns the user's real name.
   * @return (string) - it may be empty if it has not been entered yet.
   */
  public final function getRealName() {
    return (string) $this->firstName.' '.$this->lastName;
  }
  

  /**
   * Returns the user's first name.
   * @return (string) - it may be empty if it has not been entered yet.
   */
  public final function getFirstName() {
    return (string) $this->firstName;
  }
  
  /**
   * Returns the user's last name.
   * @return (string) - it may be empty if it has not been entered yet.
   */
  public final function getLastName() {
    return (string) $this->lastName;
  }
  
  /**
   * Returns the user's email.
   * @return (string)
   */
  public final function getEmail() {
    return (string) $this->email;
  }
  
  /**
   * Add an entry into the access log
   */
  public static function poppop() {
    DATABASE::connect();
    @mysql_query(sprintf("INSERT INTO AccessLog
    (`user`,`ipAddress`,`url`,`agent`,`serializedSession`,`serializedServer`) VALUES
    ('%s','%s','%s','%s','%s','%s')", 
    DATABASE::ESC(@$_SESSION['user']), DATABASE::ESC($_SERVER['REMOTE_ADDR']),
    DATABASE::ESC($_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI']),
    DATABASE::ESC($_SERVER['HTTP_USER_AGENT']),
    DATABASE::ESC(serialize(@$_SESSION)),
    DATABASE::ESC(serialize($_SERVER))));
    DATABASE::mysqlDebug();
  }
  
  /**
   * Destroy's the user's session.
   * @return (bool) true if it worked, otherwise false... if false you have some server issues to work out
   */
  public final function logout() {
    return (bool) session_destroy();
  }

}

?><?php

Abstract class Viewer extends User implements SplSubject{}

Final class Interviewer extends Viewer implements SplObserver{}
class Admin extends User implements SplObserver{}
final class Applicant extends User implements InnerIterator, SplSubject{}

/**
 * A Reviewer has access to view and vote on preselected applications.
 *
 * @author new2net
 * @package net.phantomcircuit.internships
 */
Final class Reviewer extends Viewer implements SplObserver{
  // Oh that's nice. I can reuse the same functions because both a reviewer, administrator, interviewer, and applicant are all users who log in.
  // well how can I make an instance identify itself?... easy, use $this->getIdentity(); That level of abstraction was handled immediately:
  /**
   * StdObject
   * 
}

?>

So this really begs the question: "Why does anyone care?". Because you can create a powerful library / API / wrapper for lots of difficult jobs and then reuse it. This is important because copy + pasting code is not just really sloppy, but does not always achieve the result you expect, and can lead to an incredible amount of refactoring.

A difficult problem can be looked at as a set of smaller problems, which have reusable solutions.

Nested Classes

Not only can someone create a class, but they can create classes and interfaces insider other classes and interfaces! It's almost an art.

Supported in (that I know of): Scala, Python, Java

Java Example of a Linked List. The nested classes are the Empty (SINGLETON), and Node classes. A LinkedList is useful for creating an unbound stack, balanced trees, binary trees, and very short lists. My implementation does not support mutating the list.

package new2net;



import new2net.LexicographicalComparator;

import java.util.AbstractCollection;

import java.util.Iterator;



/**

 * @author new2net (irc.freenode.net)

 */



abstract class SchemeList<T> extends AbstractCollection<T> implements Comparable<T> {



  public interface Fun<T, T2> {

    T2 apply(T obj);

  }



  public interface Proc<T> {

    void apply(T obj);

  }



  private static class Node<T> extends SchemeList<T> {

    

    private T head;

    private SchemeList<T> tail;



    public Node(T head, SchemeList<T> tail) {

      this.head = head;

      this.tail = tail;

    }



    @Override

    public T head() {

      return head;

    }



    @Override

    public SchemeList<T> tail() {

      return tail;

    }



    @Override

    public int length() {

      return tail().length() + 1;

    }





    @Override

    public SchemeList<T> append(SchemeList<T> list) {

      return list == EMPTY ? this : new Node<T>(list.head(), append(list.tail()));

    }



    @Override

    public int size() {

      return length();

    }



    //abstract public <T2> SchemeList<T2> map(Fun<T, T2> f);



    @Override

    public <T2> SchemeList<T2> map(Fun<T, T2> f) {

      return new Node<T2>(f.apply(head), tail.map(f));

    }



    @Override

    public void forEach(Proc<T> f) {

      f.apply(head);

      tail.forEach(f);

    }



    @Override

    public String toString() {

      Iterator<T> toStringIterator = iterator();

      StringBuffer tempString = new StringBuffer("(");

      

      while(toStringIterator.hasNext()) {

        tempString.append(toStringIterator.next() + " ");

      }



      tempString.deleteCharAt(tempString.length() - 1);

      return tempString + ")";

    }



    @Override

    public int compareTo(T o) {

      return new LexicographicalComparator().compare(head.toString(), o.toString());

    }





    @Override

    public int hashCode() {

      final int prime = 31;

      int result = 1;

      result = prime * result + ((head == null) ? 0 : head.hashCode());

      result = prime * result + ((tail == null) ? 0 : tail.hashCode());

      return result;

    }



    

    @Override

    public boolean equals(Object obj) {

      if (!(obj instanceof Node))

        return false;

      

      //this should work now that I know it's of type Node and not null

      return hashCode() == obj.hashCode();

    }



  }



  private static class Empty<T> extends SchemeList<T> {

    @SuppressWarnings("serial")

    private static class Exception extends UnsupportedOperationException {}



    // default constructor -- nothing to construct

    

    @Override

    public T head() throws Exception {

      throw new Exception();

    }



    @Override

    public SchemeList<T> tail() throws Exception {

      throw new Exception();

    }



    @Override

    public SchemeList<T> append(SchemeList<T> list) {

      return list;

    }



    @Override

    public int length() {

      return 0;

    }



    @Override

    public String toString() {

      return "()";

    }



    @Override

    public int size() {

      return length();

    }



    @SuppressWarnings("unchecked")

    @Override

    public <T2> SchemeList<T2> map(Fun<T, T2> f) {

      return (SchemeList<T2>) this;

    }



    @Override

    public int compareTo(T o) {

      return new LexicographicalComparator().compare("", o.toString());

    }



    @Override

    public boolean equals(Object obj) {

      // TODO Auto-generated method stub

      return false;

    }



    @Override

    public void forEach(Proc<T> f) {}



  }



  /**

   * @author RLa (irc.freenode.net #java)

   */

  private static class SchemeListIterator<T> implements Iterator<T> {

    private SchemeList<T> list;



    public SchemeListIterator(SchemeList<T> list) {

      this.list = list;

    }



    @Override

    public boolean hasNext() {

      return list != EMPTY;

    }



    @Override

    public T next() {

      T head = list.head();

      list = list.tail();

      return head;

    }



    @Override

    public void remove() {

      throw new UnsupportedOperationException();

    }

  }



  /**

   * This is the empty list. Use it to build new lists. All lists end with the

   * empty list.

   */

  public static final SchemeList<?> EMPTY = emptyList(); /* what a freaking mess! stupid generics!!! */



  private static final <T> SchemeList<T> emptyList() {

    return new Empty<T>();

  }

  

  private SchemeList() {} // You must use the emptyList "EMPTY"



  abstract public boolean equals(Object obj);



  /**

   * @return The datum in the link list Node

   * @throws Exception

   *           if the node is an empty list.

   */

  abstract public T head();



  /**

   * @return The node (if it exists) linked to the invoking node.

   * @throws Exception

   *           if the node is the empty list.

   */

  abstract public SchemeList<T> tail();



  /**

   * returns the length of the list, 0 if the list is empty.

   * 

   * @return the length of the list.

   */

  abstract public int length();



  abstract public String toString();



  /**

   * Takes any object and links it to the end of the invoking list as a new

   * SchemeList Node with the object in the "head" of the list.

   * 

   * @param obj

   *          - any object

   * @return SchemeList

   */

  public SchemeList<T> cons(T obj) {

    return new Node<T>(obj, this);

  }



  /**

   * Takes all of the nodes from the argument "list" and uses cons to link them

   * to the invoking list.

   * 

   * @param list

   *          SchemeList whos nodes will be attached to the invoking list.

   * @return SchemeList - a new list with the invoking lists nodes preceded by

   *         the nodes in the list passed to append.

   */

  abstract public SchemeList<T> append(SchemeList<T> list);



  /**

   * Applies an anonymous function to the invoking list, and returns a new

   * list (in the same order) with values processed by the anonymous function

   * Fun.apply().

   * 

   * @param f

   *          - SchemeList.Fun.apply (an anonymous function)

   * @return - A list in the same order as the one which called map()

   */

  abstract public <T2> SchemeList<T2> map(Fun<T, T2> f);



  /**

   * Goes through the list in order passing each SchemeList node as an argument

   * (Object) to an anonymous function SchemeList.Proc.apply().

   * 

   * Note that forEach() does not return any value, unlike map().

   * 

   * @param f

   *          - SchemeList.Proc.apply (an anonymous function)

   */

  abstract public void forEach(Proc<T> f);



  /**

   * Compares the parameter o to the current head using lexicographical ordering.

   * If the invoking list is empty, then the parameter o will be compared to an

   * empty string.

   * 

   * @param o - The object to be compared

   * 

   * @return   -1 (o comes before the current list element), 

   *            0 (o equals the current list element), 

   *            1 (o comes after the current list element).

   *            

   * @throws ClassCastException if the specified object's type prevents

   *         it from being compared to this object.

   */

  abstract public int compareTo(T o);

  

  @Override

  public final Iterator<T> iterator() {

    return new SchemeListIterator<T>(this);

  }



  

  

}

Package

A package is a set of code. One should also hope for documentation along with a package, although that doesn't always happen. Some packages might be "crypt", "cgi", "mysql", and so on. A package does not imply that classes are declared. It's intended to be scalable and reusable code.

So, is there any OOP support in AutoItv3?

Link to comment
Share on other sites

Hi and Welcome to the forums!!

  • Block

    • Nope, but you could get similar effect by using a function with a Local variable instead of the block.
  • Function

    • :)
  • Class

    • AutoItObject UDF
  • Nested Class

    • Repeat previous answer
  • Package

    • #include ?
  • So, is there any OOP support in AutoItv3?

    • Third time's the charm?
Edited by AdmiralManHairAlkex
Link to comment
Share on other sites

I can not find any documentation for that code/package. Please advise

Documentation as in "How to use this, what this supports". Try clicking on the website's "Documentation" tab- I think they got the pages mixed up, that looks like a FAQ.

Edited by new2net
Link to comment
Share on other sites

  • Moderators

new2net,

Searching (the Search box is at top right :)) for AutoItObject will bring up this thread as the top hit.

Please do not ask me to explain it - it is way above my level - but those that do say it works well. Have fun! ;)

M23

Public_Domain.png.2d871819fcb9957cf44f4514551a2935.png Any of my own code posted anywhere on the forum is available for use by others without any restriction of any kind

Open spoiler to see my UDFs:

Spoiler

ArrayMultiColSort ---- Sort arrays on multiple columns
ChooseFileFolder ---- Single and multiple selections from specified path treeview listing
Date_Time_Convert -- Easily convert date/time formats, including the language used
ExtMsgBox --------- A highly customisable replacement for MsgBox
GUIExtender -------- Extend and retract multiple sections within a GUI
GUIFrame ---------- Subdivide GUIs into many adjustable frames
GUIListViewEx ------- Insert, delete, move, drag, sort, edit and colour ListView items
GUITreeViewEx ------ Check/clear parent and child checkboxes in a TreeView
Marquee ----------- Scrolling tickertape GUIs
NoFocusLines ------- Remove the dotted focus lines from buttons, sliders, radios and checkboxes
Notify ------------- Small notifications on the edge of the display
Scrollbars ----------Automatically sized scrollbars with a single command
StringSize ---------- Automatically size controls to fit text
Toast -------------- Small GUIs which pop out of the notification area

 

Link to comment
Share on other sites

I can not find any documentation for that code/package. Please advise

Documentation as in "How to use this, what this supports". Try clicking on the website's "Documentation" tab- I think they got the pages mixed up, that looks like a FAQ.

There's a .chm in the download, and lots of examples there and in the thread.

Sorry about not putting in a link, I usually do that but it slipped.

Link to comment
Share on other sites

As stated previously, there is NO support of anything but functions. The autoit parsing model is a simple one.

There are, however, some preprocessors and UDFs that will add that functionality.

My favorite is au++

Edited by hyperzap

ongoing projects:-firestorm: Largescale P2P Social NetworkCompleted Autoit Programs/Scripts: Variable Pickler | Networked Streaming Audio (in pure autoIT) | firenet p2p web messenger | Proxy Checker | Dynamic Execute() Code Generator | P2P UDF | Graph Theory Proof of Concept - Breadth First search

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...