eclipse-archived / ceylon

The Ceylon compiler, language module, and command line tools
http://ceylon-lang.org
Apache License 2.0
399 stars 62 forks source link

properties or attribute setter references #3791

Open CeylonMigrationBot opened 11 years ago

CeylonMigrationBot commented 11 years ago

[@gavinking] We've discussed this many times before. Do we need a way to get a reference to an attribute that you can invoke to get/set it. This is very useful for UI code, where you would be able to just easily attach a textbox to a String attribute, for example.

Proposed solution:

//for instance members
String(String=) nameAtt = person.@name;
String name = nameAtt();   //get the name
nameAtt("New name");   //set the name

//also for static refs
String(String=)(Person) nameAtt = Person.@name;
String name = nameAtt(person)();   //get the name
nameAtt(person)("New name");   //set the name

Thoughts?

P.S. Note if name were non-variable, then the type of the function would be just String().

[Migrated from ceylon/ceylon-spec#685]

CeylonMigrationBot commented 10 years ago

[@FroMage] This Property object may be something we want to merge with the current Value metamodel. You also need to define the semantics of listeners wrt exceptions. I still think we should not introduce listeners to attributes without interceptors to methods, as I don't like the increasing difference between attributes and methods. I also don't quite like the third new model types that this would introduce: properties, metamodel and meta-declarations.

If you're convinced we must introduce listeners, we should address all this is one go. If all we need are attribute references, we should make them as close as possible to method references, minus the required extra syntax.

CeylonMigrationBot commented 10 years ago

[@gavinking]

This Property object may be something we want to merge with the current Value metamodel.

Perhaps, but Value seems to me something that is significantly more heavyweight. We distinguish between Callables and Methods for the same reason.

I also don't quite like the third new model types that this would introduce: properties, metamodel and meta-declarations.

I'm not sure that this is a new layer. I think it conceptually lives in the same layer as Callable.

I still think we should not introduce listeners to attributes without interceptors to methods

In principle I agree with you, but given the narrow bandwidth we have right now for new language features, I think we should focus attention on which of these features is more critical, and that, at least right now, is properties, not interception.

CeylonMigrationBot commented 10 years ago

[@gavinking] By the way, @FroMage, I'm not even convinced that property notifications == interception. They might be distinct facilities. Interception to me would imply the ability to listen to attribute get operations as well as attribute set operations. Also, I had always envisaged that interception would be something at the metamodel level, and perhaps even be limited to static interception (i.e. class-level rather than instance-level interceptors).

Property notifications are:

So I'm not totally convinced that they're part of "interception".

CeylonMigrationBot commented 10 years ago

[@FroMage]

I think it conceptually lives in the same layer as Callable.

Except Callable has no methods, and we're now talking about a Property with methods and adding the same to Callable.

You're right that the metamodel is heavier, but this may be something we could fix with lazy(er) initialising.

So I'm not totally convinced that they're part of "interception".

I'm pretty sure they intersect a lot. Or will.

CeylonMigrationBot commented 10 years ago

[@gavinking]

I'm pretty sure they intersect a lot. Or will.

Maybe. If we deicide that interception is an instance-level thing then yes, I suppose they will.

CeylonMigrationBot commented 10 years ago

[@marvelous] What I would need is a static reference to a JavaBean property.

// Java
class Person {
private String name;
public String getName() { return name; }
public void setName(String name) { this.name = name; }
}

// Ceylon
Property<Person, String> prop = `Person.name`

A bit like the JPA metamodel really, but for the JavaBeans spec. http://www.oracle.com/technetwork/java/javase/documentation/spec-136004.html

With:

The spec is very old, but some parts are still used as-is.

I think the Property change pattern doesn't need language support.

CeylonMigrationBot commented 10 years ago

[@vietj] @marvelous I have some kind of property in Cayla MVVM:

https://github.com/vietj/cayla-mvvm/blob/master/source/io/cayla/mvvm/Property.ceylon

CeylonMigrationBot commented 10 years ago

[@gavinking] @vietj

property navigability (composition)

it is essential for proper addressing complex cases, specially for templates in which bind property > references and not instances. It looks like static property ref composition address this case.

Upon reflection it might be better to support something more like:

@Person.address.country

Than the much more verbose:

@Person.address.compose(@Address.country)

That is likely doable. We need to think it through.

multi valued properties

do you plan to address this case ? (list) or should it be handled by frameworks using collection wrappers.

I suppose you mean events when things are added/removed to/from a collection. Dunno, we need to discuss this. I can see a couple of different ways that it could work.

computed

need also something for creating computed observable properties :+1:

I think my proposal already covers that, doesn't it? The fake examples.

CeylonMigrationBot commented 10 years ago

[@gavinking] Note that the syntax for computed properties would be much nicer with #3627 and/or #3439. Consider:

@String fake = Property {
    val=>”hello”;
    assign val {}
};
CeylonMigrationBot commented 9 years ago

[@EricSL] This can be combined with a pass-by-reference syntax.

So in C#, you can do:

void main() { int x = 2; addTwo(ref x); // x == 4; }

void addTwo(ref Integer x) { x += 2; }

So bringing this into the Ceylon world, I would suggest a new class Reference which just holds a getter/setter pair of type T. Then we could add the above syntax as syntactic sugar, where in an expression "ref x" creates a Reference that modifies the value of x, and in a variable declaration "ref T x" declares a variable that must initially be bound to a Reference, but after that any further accesses or modifications to x are invoking the reference's getter/setter pair.

So this syntax would enable pass-by-reference, but it would be much more powerful because you could provide a reference to a property on a class, you could store references, and so it would enable the features you're thinking about here as well.

CeylonMigrationBot commented 9 years ago

[@gavinking] @EricSL Well that doesn't look that different to my proposal above, AFAICS.

CeylonMigrationBot commented 9 years ago

[@EricSL] Yes it is quite similar.

Just a few things to clarify:

@String nameOfPerson = @person.name;

Is this a bug? Elsewhere you write things like "person.@name". Or does this create a reference that changes value when either person or person's name changes? This is hard to specify, as "@person" is a Property which does not have a property "name".

shared @String @name = name.@fullName;

So when other code gets/sets name, does it get/set a String or a Property? I would say it is a String, so I would write this "shared String @name = name.@fullName;". One could also have properties where you get/set Propertys, and even references to such properties, so I would say it is different.

I guess an advantage of "ref" is that you might want more kinds of references (e.g. "out" to just capture the setter), and another keyword if we add support for an observer. But the advantage of @ is that you can put it anywhere in a sequence of properties (@person.name or person.@name) whereas if those are different things with ref you would do "ref person.name" or "ref (person).name".

CeylonMigrationBot commented 9 years ago

[@gavinking]

@String nameOfPerson = @person.name;

Is this a bug? Elsewhere you write things like "person.@name".

I think it's a misprint. I wrote that up a while ago.

shared @String @name = name.@fullName;

So when other code gets/sets name, does it get/set a String or a Property?

What this syntax is doing, essentially, is creating an alias of name.fullName.

It's saying that @name is of type @String, ∴ name is of type String. You see?

So writing:

name = "Gavin";

would set name.fullName to "Gavin".

One could also have properties where you get/set Propertys, and even references to such properties, so I would say it is different.

Yes, that would be:

shared variable @String nameProperty = name.@fullName;

Here nameProperty is of type @String, not of type String.