What’s in a Name: Variable and Constant bindings

As in most languages, Grace lets you bind names to values. In Grace’s case, the values are always objects. Some bindings are constant, that is, they don’t change until the names goes out of scope; others are variable, which means that the name can be re-bound to a new value. This re-binding is accomplished using assignment.

Constant Bindings

Constant bindings are used to bind method parameters to the arguments of the message that started the method execution. Grace supports constant bindings with the keyword const.

Const requires a name to define, and either or both an initialiser and a type. Const can be used to give a name to a literal, or to any other object.

If there is no initialiser, the identifier must be assigned (using =) before it is used.

The point of definitions like “const x : Rational” or const x — without an initialiser — is that in class definitions, they will be used to define per-instance constants that will be initialised when the object is constucted. For example, a point in Grace would declare two constants “x” and “y” — which would differ for each instance.

Uninitialised variables (of any type) are given a special “uninitialised” value; accessing this value is an error (caught either at run time or at compile time, depending on the cleverness of your implementor).

Variables

Naturally enough, Grace supports variable declarations via the “var” keyword.

Unlike constant name bindings, variables can be re-bound using assignment “:=”

Note that const uses = initialisation, while var uses := for both the initial and subsequent bindings.

As in Java, both const and var declarations may occur anywhere within a method or block: their scope is to the end of their defining block or method.

Fields

Within object or class constructors, fields are declared by the field keyword rather than var.

The idea here is that classes will contain methods defined by the method keyword, and fields defined by the field keyword. We are hoping that we can choose Grace’s keywords to guide the terminology used in discussing the language.

Const declarations an also appear in object and class constructors, to define per-instance constants.

Single Namespace

Grace has a single namespace for methods and variables. This means that methods should be able to override fields, and fields override methods.

A declaration of field or a constant named “x” creates a reader method called “x”. A declaration of a (writable) field creates a setter method called “set_x”. All code of the form “e1.x := e2” is executed by sending the “set_x” setter method to the object e1, passing e2 as an argument.

The upshot of this is, if a Grace program declares a pair of methods in an object:

clients (and subclasses) of that object are unable to distinguish this from a field declaration

This ensures that fields and constants are evaluated in Grace using the same message send evaluation rule as method sends.

Types

We haven’t mentioned types. That’s because we haven’t worked out the even the initial details – but that’s what we’ll look at soon.

Decisions

This note outlines our current design of Grace. We have a few questions or concerns about this design:

  1. Should Grace distinguish between var to declare temporary variables and field to declare instance fields – or if not, which one should we pick?
  2. Should Grace distinguish between := for mutable fields and variables, and = for constants?
  3. How should Grace name setter methods?  “set_x” or “s:=” or something else.

BNF


15 thoughts on “What’s in a Name: Variable and Constant bindings

  1. The distinction between var and field is gratuitous. A var is a mutable storage location, a const is an immutable one. This holds for instances of classes, and for method activations (which are just object as well).

  2. The use of := for setter method is understandable. There is no need for set_x etc. Let people declare x:= as a method. It isn’t as elegant as Smalltalk syntax, but I understand the urge to pander to the mainstream. Hvaing both set_x and x := is a mess however.

  3. Re: field and var – yes they are basically the same thing, but the difference between the “heap” and the “stack” isn’t quite so gratuitous, even in the presence of closures. This is somewhere where we may break symmetry to support first year teaching – although really we would like more feedback about this.

  4. I agree with Gilad about field vs. var. The problem of this distinction is also that if you want a constant field, then you’ll have to combine const and field. Ie., field does not really bring anything, while var and const have deep meanings (identifiers vs. variables, in PLAI terminology, which I like best than “const bindings” btw).

    In addition to this non-orthogonality argument, of one of the essential “values” for Grace is simplicity for 1st year students, I don’t think it is justified to have this notational overload to distinguish fields, which would be anyway distinguishable.

  5. “A declaration of field or a constant named “x” creates a reader method called “x””

    — such a choice does not reflect the fact that fields are means to potentially implement an interface (which in turn suggests the semantics of field shadowing, as opposed to late-bound overriding).

    Bottom line is: why should declaring a field have impact on the interface of an object? (ie. by adding a method to the set of understood messages) It seems to me that the strongly encapsulated model where all fields are private and only accessible within methods (ie. field accesses are always on `this’) support better OO design by focusing on a selective object interface. Automatically generating getters/setters will pollute the real interface of an object with all its implementation details.

    (of course I might be missing something about visibility identifiers somewhere else, but since we’re talking about a beginner’s language, I’d hope the procedural interface of objects would be enforced from the start)

  6. “A declaration of field or a constant named “x” creates a reader method called “x””…

    Éric, I’m not sure why this suggests shadowing vs overriding – Grace will use the One True Message Send evaluation rule for invoking all messages and for reading and writing fields. Grace’s design here follows Self, Scala, and Eiffel.

    In these languages, a may field appears in an interface as a getter/setter pair: because fields can always be exchanged for methods (or vice versa) there are fewer software engineering issues than in languages where fields can never be overridden.

    We haven’t started talking about a module system yet, but we expect that it will allow the accessibility of both fields and methods to be controlled.

    We hope to support a range of different pedagogical approaches with Grace: either making all fields private and requiring explicit accessor methods as necessary, or allowing public (pseudo) fields as necessary (e.g. Java Beans style). The single namespace also means that Grace subsumes C#-style properties without specialised language support.

  7. The problem of this distinction is also that if you want a constant field, then you’ll have to combine const and field

    In the current design, if you want a “per instance” constant (I think that’s what you mean by a constant field) then you’d just write “const“.

    In this design, const would work in any scope; field only inside object and class declarations; and var only outside such declarations.

    The obvious alternative we’re considering is to just use const and var. (We prefer const to Scala’s val — partly because we want to use the term “value types” for, well, value types — deeply immutable objects).

  8. “Éric, I’m not sure why this suggests shadowing vs overriding”

    I meant to say the reverse (sorry my blog english is a bit confusing it seems ;)).
    Having a field yield an accessor method of its name, means that a subclass can override a field access (since it’s just a message send). This differs from the semantics of field shadowing, which ensures that methods declared in a class refer to fields declared in that class or superclasses, but not in subclasses. (ie. using a field to implement the public API of the object is kept as an internal decision, not subject to open recursion)

  9. Having a field yield an accessor method of its name, means that a subclass can override a field access

    yes that’s right – I’m not sure whether you prefer it that way or not. In some ways a Smalltalk style “dual namespace” makes for easier encapsulation (I wonder how related this distinction is to 1-Lisp vs 2-Lisp?). But often, before the end of the first year, people will have to come up against things like Java Beans or C# “properties” – a single namespace simplifies those issues.

    And, for encapsulation, programs need private methods as well as private fields. We hope to tackle encapsulation & modularity in a way that is orthogonal to methods & fields.

  10. Ok, I get it. I guess I prefer having all fields private and a language with strong encapsulation in which a field access is always on self (ie. not possible to access a foreign field). This makes it clearer that fields are parts of the implementation strategy an object might choose for its API.

  11. Very interesting exploration process! The more I read it, though, the more I wonder whether you’ve thoroughly considered Ruby. It seems to me to have a very similar design mindset, as well as the obvious practical advantage of already existing.

  12. Hi Glenn

    The short answer is that we have considered Ruby (although perhaps not as much as we should have). In many respects the languages will be similar, perhaps because the design of both is quite heavily influenced by Smalltalk. The biggest difference is that Grace will have a type system – closer to Mike Furr & co’s Diamondback Ruby (DRuby) than Ruby itself.

  13. Eric – This makes it clearer that fields are parts of the implementation strategy an object might choose for its API.

    I hope that this can still be the case – we want to support teaching about encapsulation and separation of interface and implementation – but this can be orthogonal to whether an API is implemented as a field, as a method, or some combination of the two.

Leave a Reply

Your email address will not be published. Required fields are marked *