Fields

This weeks Elememts build brings three new and exciting language features to the Oxygene language – and they all center around a single new keyword: field.

Field-Backed Properties

Things started off by bringing one of the new C# 14 features to Oxygene: Field-backed Properties.

Field-backed properties solve the conundrum where, as soon as you want a property to do anything more complex than just store and retrieve a value straight-up, you need to manually declare a field to store its value in by hand. With the new syntax, you can let the compiler handle that part for you, but still provide custom getter or setter code. And you can use the new field keyword (same in C# and Oxygene) to access the "backing field" from inside that code.

In C#:

private string _msg;
public string Message
{
    get { return _msg; }
    set 
    { 
        _msg = value ?? throw new ArgumentNullException(nameof(value)); 
    }
}

Now simply becomes

public string Message
{
    get;
    set 
    {
        field = value ?? throw new ArgumentNullException(nameof(value));
    }
}

No manual getter code; no private field declaration, no msg cluttering up the class's scope. And, most importantly, no chance to accidentally access _msg directly from other pasts of the class.

The same concept applies to Oxygene:

property Message: String write begin
  field := coalesce(value, raise new ArgumentException(nameOf(value));
end;

Any property that uses the field keyword in its read or write code becomes a field-backed property.

Also, any field-backed property will be read/write, and get its default read or write Implementation implied, if not specified, like in the example above. Why can we assume that's the intention? Because a read-only or write-only field-backed property would be pointless – who else would read (or write) its value, otherwise?

Field-backed Properties for Oxygene are documented in full, here.

Fields

Now that we have a field keyword in Oxygene anyways, this opened up the door for additional opportunities.

I have long been a proponent of proper naming, because the way we call things shapes the way we think about them. It's one of the takeaways I got from the excellent book Object Thinking, and one of the reasons why – as far back as version 1.0, before it was even called Oxygene – I pushed for the introduction of the method keyword to the language. Because Classes do not provide functions and procedures (and there are additional arguments on why Pascal's terminilogy re functions and procedures is bad – but that is for another day), they provide methods. So it feels only right to use the method keyword to declare them.

Another thing classes (and records) contain is fields. In fact, a class without fields is not much of a class. Even though fields are (usually) variable, as in mutable, they are not variables! Yet, what (optional, alas) keyword did we use to declare fields? var.

No more! As of today, the field keyword can be used inside a class or record declaration to declare one or more fields, replacing var as the preferred and suggested option.

Of course, var will continue to work, for backwards compatibility; just as function and procedure are still there to this day, if you prefer. But field is the way to go.

Field type members in Oxygene are documented in full, here.

Local Fields

But we did not stop there.

The third and probably coolest application of the field keyword is inside code, i.e. in the body of your methods.

Of course, the var keyword sticks around for declaring variables inside your code, whether in a var section at the top of your method, or – the preferred Oxygene way since 2004 – inline with the var statement.

This is not changing. But we've introduced a new field statement that follows the same semantics, but will declare a field on class-level – but scoped to be accessible only in the current method or scope. The field will be initialized the first time the line declaring it is hit, and after that, its value will persist across all future calls to the same method (on the same instance).

Essentially, a local field is like declaring a regular private (all fields should be private) field, but limiting access to it to a single method or scope within a method.

  • Local fields can be instance (the default) or static for the class when using class field or the static modifier. (same as for regular, global fields).
  • Local fields in a static method or a static class will, of course, always be static.
  • Local fields in an instance constructor need to be static (because what would be the point, otherwise) and are not supported in a (static) class constructor.

For example, this Log method keeps internal track of indentation level, based on what strings it got sent to writeLn:

    method Log(aMessage: String);
    begin
      field fIndent := 0;
      if aMessage.StartsWith("<-") then
        dec(fIndent, 2);
      writeLn("".PadEnd(fIndent, ' ')+aMessage);
      if aMessage.StartsWith("->") then
        inc(fIndent, 2);
    end;

Local Fields for Oxygene are documented in full, here.

Get All Your Fields Now!

All of these (and field-backed properties in RemObjects C#, of course) are available in Elements .3057, out on the Preview channel today. We expect next week's .3059 to bring them ot the Stable channel and the free trial.

Read more about Elements here. New stuff is being added to Elements every week.