Proposal: Local properties

Edit: Changed the request to Local properties, as this is the solution for the other proposal and has much more value then the request below.

Rem Objects Elements has Non Nullable references, which are implemented like they are implemented in c# 8.0 (as I understand it).
With this implementation, the compiler checks agains possible null assignments - and all those possible null assignments are not allowed, making it very hard to use them.

I’d like to advocate for a solution that solves this problem; instead of using Non Nullable references i’d like to use Non Nullable Objects. A Non Nullable Object is an object with a default value.
After each assignment the compiler adds a check to see if the non nullable Object became null and if so, the default value is assigned to it, making sure that the object will never be null.

The difference: With a Non Nullable Reference the compiler is trying to prevent that a null reference is ever assigned. With a Non Nullable Object, a null reference is simply replaced by a default value.

To elaborate the following code:

//normal reference
var s: String; //value of s is null

//Non Nullable Reference
var x: Non Nullable String := "";
 
//Non Nullable Object
// the default can be anything that returns an instance of this object type, 
// in this case a constant, but it can also be New String or the result of a function.
var y: String; default ""; //value of y is now ""

x := s; //will not compile because you assign a nullable object to a non nullable object
y := s; //will compile, y will be "" after this call

It is much simpler to use a non nullable Object than a non nullable Reference, as a Non nullable object can always be assigned to and it will never, ever be null. (Unless you define the default as a function that returns null, but that would be silly).

A possible implementation:

var _y: String := ""; //the default is assigned here
method _ym(value: String);
begin
    if value = nil then 
        _y := "" //the default is assigned here
    else
        _y := value;
end;
property y: String read _y write _ym;

But for local var’s this requires a local property - not possible at this moment as far as I know.

We’ve been discussion this a bit internally.

I don’t think it’s a bad idea, per se, but right now. nullable and. non-nullable types pretty intentionally work exactly the same for value and non-value types.

You cannot assign nil to an Integer to make it nil, you must assign 0 or default(Integer); same goes for records. a non nullable class type behaves the exact same. The idea s that essentially the only difference between class and value types (what nullability is concerned),s the default nullability.

  • nullable Integer behaves same as nullable String, and
  • not nullable Integer behaves same as not nullable String.

That doesn’t preclude us doping the feature you suggested, but I’d see it decoupled from nullability, more as a “variable with default value”. My concern then, though, would be how intuitive this feature really is.

Can you give me a concrete use case where tis would be useful — ideally decoupled from String, which I understand holds a more special role (and e.g. Delphi treats empty strings and nil strings the same; something that can be replicated specifically for strings better in different ways, for example Delphi RTL’s value-based string type does this).

The idea is twofold:

  1. completely eliminate the possibility of a null reference (with 100% garantee)
  2. having a user defined default on an(y) object

The first one could also be done with a immutable reference (readonly variable).
But that means that the reference can not be replaced so it cannot be used on a function call where the result of the function has to be assigned and not on a parameter that is defined as out.

The second one: I do not want a null reference in all cases but a sometimes a kind of default instance instead of the null reference.

Examples of defaults I would use:

  • an empty list on a list object
  • an empty string (or another default(!)) on a string object
  • on an order, relation, article, … object where the user can open an existing one
    -> if not found null is returned -> replaced by the default (new object with all defaults in all fields)
    This eliminated the check on nil and assigning a default, I can now just show it in the UI.

But, as I think of it, the whole problem can be solved as soon as we have local properties (see my second post).
And that is a much more powerfull tool, as any local variable can be replaced by a property implementation if needed.

So I change my request to: Please implement local properties.

I agree, I see that as more feasible/sensible. I’ll log a feature request (but I’ll be honest, it will be low priority as we do have a lot of stuff going on right now on the compiler front and Carlo is just starting two weeks of leave, as of tomorrow.

On an unrelated note: how about a beach on Saturday :beach_umbrella:? We’ll be going to Kenepa Grandi…

—marc

Thanks, logged as bugs://82112

No problem at all.
For the unrelated note, see my PM.

1 Like

Changed the title.

1 Like

Just a little reminder to keep it on the charts :innocent:

bugs://82112 got closed with status fixed.

basically all features of properties:

  • Readonly
  • With initiailizer
  • With read/write expression
  • Write read/write lambda / statement

None of the modifiers work, only readonly (override/virtual don’t make sense here).

it works by a combination of inline methods and property helpers, the scope is limited to the containing begin/end block.

method Test;
begin
  var i := 15;
  property TestA: Integer;
  property TestB: Integer := 9;
  property TestZZ: Integer read i + 1;
  TestA := 11;
  TestB := 9;
  writeLn(TestA);
  writeLn(TestZZ);
  inc(i);
  writeLn(TestZZ);
end;
1 Like

Carlo, thank you very much!!!

i was gonna ask Carlo to do this for your birthday, but he beat me to it :wink:

1 Like

Just installed the new version, and it works like a charm :sunny:

1 Like