Prevent subclassing1. 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 methods1. 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 THISPython 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 methodsWhat 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 declarationsUsually 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) } }