ReadOnly props initialization

Hello,
I’m trying to initialize read only props with .ctr as follows:

namespace SimpleClassTest;
type
  SimpleClass = public class
  public  
    property MyReadOnlyProp1: Integer; readonly; required;
    property MyReadOnlyProp2: Integer read private write; required;
  end;
  Program = class
  public
    class method Main(args: array of String): Int32;
    begin      
      var lSimpleClass := new SimpleClass(
        MyReadOnlyProp1 := 10,
        MyReadOnlyProp2 := 20
      );
    end;
  end;
end.

But compiler raises an error

E: Property "MyReadOnlyProp1" on type "SimpleClass" is read-only [W:\_TMP_\RemObjects Samples\Examples\SimpleClassTest\Program.pas (19)]
E: member "MyReadOnlyProp2" on type "SimpleClass" cannot be called because it is private [W:\_TMP_\RemObjects Samples\Examples\SimpleClassTest\Program.pas (20)]

What is my misunderstanding in:
Properties (elementscompiler.com)

Thank you,
Giovanni

Hi Giovanni,

I am afraid that this is “as designed”, as read-only properties need to be initialized in the constructor itself.

simply is a syntax shorthand and translates to:

temp := new SimpleClass();
temp.MyReadOnlyProp1 := 10,
temp.MyReadOnlyProp2 := 20
var lSimpleClass := temp;

and at this place in code , the properties are already inaccessible.

Thank you, Marc,
now I understand what that syntax works.

Is there an elegant way define a constructor to pass just some parameters instead to define all needed to initialize that readonly props?

Unfortunately, not currentlly :(.

maybe, a day, you’ll may consider to convert that shorthand in something to effectively run in .ctor body.

thank you,

Giovanni

The problem is, (at least on .NET), a lot of this is enforced at runtime too (at least the private-write; not sure about readonly). So the class would actually have to implement a .ctor that takes all properties as potential parameters. And .NET has pretty strict rules for how .ctors ar inherited, so “just always” introducing a hidden .ctor that can be used for this would introduce all kinds of issues (not to mention, maybe would allow setting properties you dont want a caller to set – which really is what readonly is for ;).

But I’ll think on this…

—marc

C# has a solution to this: there is a property access called init.
Init only setters - C# feature specifications | Microsoft Learn

Does that one work with the new Foo {} syntax?

Logged as bugs://E27015.

The following code compiles (.NET 8):

namespace SimpleClassTest;

public class SimpleClass
{
  public required Int32 MyReadOnlyProp1
  { get; init; }
  public required Int32 MyReadOnlyProp2
  { get; init; }
}

class Test
{
  static void DoSomething ()
  {
    var value =
      new SimpleClass
      {
        MyReadOnlyProp1 = 10,
        MyReadOnlyProp2 = 20
      }; 

   //  value.MyReadOnlyProp1 = 22;  // error
  }
}

Yeah. so http could work. now all we need is a good syntax ;).

Maybe you already have a chance.
What do you think about changing that shorthand behavior to implement init in case of .ctor?

Not sure I understand what you mean.

I have opened a ticket to investigate the issue; we just need to find a good syntax to represent the equivalent of { get; init; } in Oxygene. Ideally w/o introducing a new keyword.

I mean that

could already be a good syntax, don’t you think so?

Are there any strong limitations on just using “readonly” keyword to do that without insert a new one like “init”?

That already works, has since version 1.0 of Oxgene ;). The question is the syntax for declaring the read-only property as allowing initialization.

ie

property Foo: String; reading; WHAT??;

I think it’s not mandatory to define new keyword, why it’s not enough the “readonly” one changing the behavior of init using the already defined syntax?

What do you think is the case of inconsistent meaning using that?

P.S. sorry for my poor ability to explain what I’m trying to mean

Because right now readonly implies that only the constructor itself (i.e. code tha is under control of the class author) can set these properties. If we made all readonly properties behave like this, that will allow outside-of-the-class code to set values that are expected to not settable like that.

Ok, now understand the global view.

Thank you very much

1 Like