Design‎ > ‎Classes and Interfaces‎ > ‎

class details

Prevent subclassing

1. use the @final attribute on classes that are not to be subclassed.
        + most classes won't need it
        - easy to forget to think about subclassing

2. only allow subclassing when the @extensible attribute  is added
        + prevents subclassing unless it's possible
        - verbose, will appear in many places

Choice: 1  Keeping it simple is more important, it's too easy to add
                @extensible to all classes without checking if this is appropriate.


Object reference in methods

1. Like Python, always use a prefix:  SELF.value = 3
        + clear
        + consistent with SUPER
        - verbose
        - "SELF" is a magic name

1a. Like 1 but use THIS, as in C++ and Java

2. Like C++, use any name:     value = 3
        + short, simple
        o can be confused with any other variable, need to disallow using
           the same name anywhere in the class, e.g.:
                setValue(string _value)
                   value = _value
                }
          Or the other way around:
                string _value
                setValue(string value)
                   _value = value
                }
          It's then up to the user to make this consistent, this may lead to inconsistencies.

3. Like some C++, require prefixing an underscore:     _value = 3
        + short
        + can have method argument with the same name, e.g.:
                setValue(string value)
                   _value = value
                }
        + no confusion with other mechanisms
        o implies that no other variable can start with _
        - annoying when using class like a struct:
             CLASS Node
                string _name
                Node   _next
             }
             Node._name = "foo"

4. Use a single dot:  .value = 3
        + short
        + no confusion with other mechanisms
        - a bit unusual
        - depends on context: IF a = b
                                  .self = 1  # could mean "b.self"

5. Use $: $value = 3
        + short, simple
        + no confusion with other mechanisms
        + easy to explain: $ stands for THIS.

Choice: 5: ease of use is most important.  Disallow redefining the name for reliability.


Use SELF or THIS

Python uses "self", C++ and Java use "this".  "this" is a bit more easy to
read for people who don't know the language.  As in "this object".

Choice: THIS


Method reference in methods

What if a method name also appears as a method in another scope?

        PROC doThat()
        }
        CLASS Foo
          PROC doThat()
          }
          PROC foo()
            doThat()  # what method is called here?
          }
        }

1. Disallow obscuring methods in outer scopes
        + simple
        o may be a bit unexpected, but method appearing at outer level is
           wrong anyway

2. Allow it, call the class method
        + simple
        - may cause calling the wrong method unexpectedly, especially if
          the class method is added later.

3. Allow it, but require using THIS:
        - too verbose, there can be many method calls

Choice: 1.  Reliability is more important


Forward declarations

Usually an identifier must be declared before it can be referenced.
However, in some cases this is difficult to achieve.  Especially when methods
depend on each other.

1. Allow forward declarations everywhere
        - makes it very unpredictable where something is to be found

2. Allow forward declarations only in classes and modules
        + this is where it makes sense
        - should encourage members to be defined at the top

3. Allow forward declarations only for methods and classes.  Member variables
   need to be defined before they are used.
        + useful
        + encourage members to be defined at the top
        - sometimes it's better to keep the variable close to where it's used
        - causes problems for including MIXINs.

Choice: 2.

Should we require that class attributes always come before methods?
No, sometimes it's useful to keep the attribute close to the method where it's
used:
        int count
        PROC tick()
          count++
        }
        FUNC getCount(): int
          RETURN count
        }

NEW() cascading

It is often useful to have several ways to create a new object.
At the same time, replicating code in multiple NEW() methods is bad.
Therefore it would be good to allow one NEW() method to call another.

Other languages have rules, sometimes complicated rules, about the
order in which an object is initialized.  We would like to keep it simple.
Let's do it this way:

  • The first NEW() that is invoked, outside of the object scope, will create
    a new object and initialize all member variables to zero/FALSE/NIL.
  • The body of the NEW() method may in invoke any other methods
    on the object THIS, including another NEW() method.
  • The NEW() method that is invoked from the object scope will use the
    object in its current state.
This allows for various cascading NEW() methods, for example:
    CLASS Foo
      string $value
      NEW() @default
        NEW("empty Foo")
      }
      NEW(string value) @default
        $value = value
      }
      NEW(int nr)
        NEW("number " .. nr)
      }
    }
    CLASS Bar EXTENDS Foo
      NEW() @replace
        PARENT.NEW("empty Bar")
      }
      NEW(string value) @replace
        PARENT.NEW("Foo: " .. value)
      }
    }

Comments