haxe-evolution
haxe-evolution copied to clipboard
New syntax for getters & setters inspired by the C# property syntax
This would allow writing a property without creating functions for each getter & setter.
@:isVar
public var property:Int { get -> property; set -> property = value; }
I like it, mostly. It does miss the default
case, although frankly I've always wondered if that was really such a good idea start with.
Still, having different syntax for the same thing tends to create confusion. I think moving forward with this should eventually lead to the deprecation and then removal of the current syntax. So we better be sure that all the cases we want to handle are handled (e.g. private set).
Maybe for the default
case, we could check for the final
modifier in the getters and setters. With this, if the user doesn't provide a getter or a setter function (an Autoproperty), it should behave like a field access. Also, that getter or setter cannot be overridden. Something like this:
public var defaultProperty:Int { final get; final set; } // This property cannot be overridden
// Translates to:
public var defaultProperty(default, default):Int;
So, for people that don't want a function call, and won't override the getter/setter, they should put the final
modifier.
What do you think?
message deleted
Maybe for the
default
case, we could check for thefinal
modifier in the getters and setters. With this, if the user doesn't provide a getter or a setter function (an Autoproperty), it should behave like a field access. Also, that getter or setter cannot be overridden. Something like this:public var defaultProperty:Int { final get; final set; } // This property cannot be overridden // Translates to: public var defaultProperty(default, default):Int;
So, for people that don't want a function call, and won't override the getter/setter, they should put the
final
modifier.What do you think?
Maybe its just me, but i think this might be more clear than the usage of final
here:
public var defaultProperty:Int { get -> default; set -> default; } // This property cannot be overridden
// Translates to:
public var defaultProperty(default, default):Int;
Then, you could also do:
public var unsettable:Int { get -> default; set -> never; }
Maybe its just me, but i think this might be more clear than the usage of
final
here:public var defaultProperty:Int { get -> default; set -> default; } // This property cannot be overridden // Translates to: public var defaultProperty(default, default):Int;
Then, you could also do:
public var unsettable:Int { get -> default; set -> never; }
Hi, I understand your point, but, what I am trying to do is not to have a 1 to 1 translation to the current property syntax. I am proposing a totally new syntax with some new behaviour, maybe the other syntax could be deprecated and removed as a breaking change in a major release. But that is out of scope of this proposal.
I think that the arrow syntax should only be used for implementations of the getter or setter, it is not only because it may be easier to parse (You just need to expect a semicolon or an arrow with expression. Semicolon = Autoproperty, Expression = Implementation/Function), it's also because I think it is cleaner and easier.
Also, I still think that the behaviour of default
or never
should be achieved with modifiers to an Autoproperty. Knowing this, I think that the default behaviour should be achieved by making/overriding a property as an Autoproperty with the final
modifier, so we don't have to include more modifiers.
With this proposal as it is, you could achieve the behaviour of never by not having a setter and never override the property to have a setter. If you would like to control that behaviour, so it also cannot be overriden, I could propose a new, never
modifier for the getter/setter that achieves that.
// This
public var unsettable:Int { final get; never set; }
// Would be the same as this
public var unsettable:Int { final get; }
// But If someone tries to implement the setter in a derived class, it will error with something like "unsettable property cannot have a setter because X declares it as unsettable".
The only thing is that it would be pointless in a lot of situations, like in static properties, those cannot be overriden, so, that modifier would just work on normal instance properties. But I think if someone does not want to have a setter I think it would be best to not implement it directly (In any of the two forms) in any class.
There's other modifier that I haven't discussed, dynamic
. My stay is that I think properties don't need dynamic functions.
As always, I am going to ask, What do you think?
Thinking about it I think I like your implementation more :) One question - I find myself overriding getters & setters from time to time. How would that be possible under this implementation?
You would override it like a normal function, with the override
modifier.
class Car
{
private var baseSpeed: Int;
public var Speed: Int { get -> baseSpeed; }
}
class FasterCar extends Car
{
public var Speed: Int { override get -> baseSpeed * 2; }
}
The only edge case that comes to my mind is if we should allow this:
class AdjustableCar extends Car
{
public var Speed: Int { override get; } // Do we create a backing field? Or should we error because we need to provide an implementation.
}
I'll update the proposal to cover this edge case, I think properties that already have an implementation shouldn't be overriden as an autoproperty.
I like this as well, I usually ignore properties as their syntax is very odd and requiring get_
or set_
leads to inconsistent styling if your codebase isn't using snake case.
I wonder if there would be any pushback over adding a new property
keyword, might avoid overloading var
and make it easier to use some different syntax. A very quick idea using anonymous structures and a property keyword.
class MyClass {
var myVar : Int;
public property myProp1 = {
get : () -> myVar,
set : v -> myVar = v
}
public property myProp2 = {
get : () -> myVar * 2
}
}
class MySubClass extends MyClass {
public override property myProp2 = {
get : () -> myVar * 3
}
}
There is already the iterator and iterable structure which classes need to unify with to support, so maybe the anonymous structures would need to unify against one of few types to be a valid property.
typedef Getter<T> = {
final get : Void->T;
}
typedef Setter<T> = {
final set : T->T;
}
typedef FullProperty<T> = {
> Getter<T>,
> Setter<T>
}
I have not thought about access modifiers, inline, final, etc, etc, or what should happen if the compiler isn't able to infer the type based on the getters and setters, so not not very well thought out! But another syntax idea in the ring based on having a property keyword.
How about having the override
on the property as a whole:
class AdjustableCar extends Car
{
public override var Speed: Int { get -> ...; set -> ...; }
}
And it would require that all property accessors that were specified on the base class must also be specified on the derived class. But have the capability to call super
to fall back to the base logic on accessors that don't need new logic in the override.
How about having the
override
on the property as a whole:class AdjustableCar extends Car { public override var Speed: Int { get -> ...; set -> ...; } }
And it would require that all property accessors that were specified on the base class must also be specified on the derived class. But have the capability to call
super
to fall back to the base logic on accessors that don't need new logic in the override.
That's another option too, it communicates that the property has a setter if you're reading the code. It's basically preference on this one, the override could be outside or inside. When you put it inside, you're communicating that you're only overriding a getter, omitting if it had a setter or not, whilst if you put it outside, you're communicating that you're overriding the entire property. I don't mind, it depends on what people do want.
You could use 'default' to only override a single part, public override var Speed: Int { default; set -> ...; }
which fits with existing usage.
Another thing to consider (I don't remember seeing anyone talking about this): in the previous syntax, a value parameter for the setter was explicitly provided:
function set_property(newValue:String) ...
If the proposed syntax is accepted, we need to either:
- come up with an exclusive keyword/parameter for retrieving the new value, which may be a little confusing, or restrict is as a field name
- provide it explicitly in the setter in some way, which might make properties a little more bloated.
@ShaharMS In the proposal I already say that the argument passed to the setter has the implicit name of 'value'. It doesn't have to be a keyword, it would be just a normal identifier. If people really want to change the name of the parameter maybe parens could be added to the setter( set(other:T) {}
) to set the argument name but it may be a little clunky.