Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bindings in CeylonFX #2

Open
renatoathaydes opened this issue Dec 2, 2013 · 14 comments
Open

Bindings in CeylonFX #2

renatoathaydes opened this issue Dec 2, 2013 · 14 comments
Milestone

Comments

@renatoathaydes
Copy link
Owner

I am currently working on this, so just wanted to add it here so everyone knows what I am trying to achieve.

My goal is to make properties in CeylonFX much easier to use than in JavaFX.
The current syntax I am pursuing is more or less like this:

value cb = CheckBox();
...
Scene {
   fill = [ cb.selectedProperty -> (Boolean sel) => sel then white else black ]
};

If properties are of the same type, then we should be able to just do:

value cb = CheckBox();
...
Scene {
   aBooleanProp = cb.selectedProperty
};

Any comments on that?

@renatoathaydes
Copy link
Owner Author

Because this will need to be generic (you should be able to bind anything to anything else, given you provide a transform function), I might have to change it to something less nice:

Scene {
   fill = bind( cb.selectedProperty, (Boolean sel) => sel then white else black )
};

Where bind is a generic function bind<From, To>(FxProperty<From> fromProp, To(From) transform).

@gavinking
Copy link
Collaborator

This is addressing the issue of binding properties of objects together, that I eventually hope to solve at the language level with a syntax like this:

shared class TextField(@text) {
    shared variable String text;
}

Person person = .... ;
TextField text = TextField(@person.name);

As proposed in ceylon/ceylon-spec#685.

But of course we need a different, temporary solution for now. Something like this:

shared class TextField(Bound<String> textProperty) {
    shared variable String text=>textProperty.get();
    assign text=>textProperty.set(text);
}

Person person = .... ;
TextField text = TextField(bind(()=>person.name,(String name)=>person.name=name));

Hell, if we think we're going to go with the idea of using String(String=) as the type of a property reference, as proposed in ceylon/ceylon-spec#685, we could even define alias Bound<T>=>T(T=); and then write:

shared class TextField(Bound<String> textProperty) {
    shared variable String text=>textProperty();
    assign text=>textProperty(text);
}

Person person = .... ;
TextField text = TextField(bind(()=>person.name,(String name)=>person.name=name));

Which is essentially with the @ stuff would be a sugar for...

WDYT, @renatoathaydes?

@renatoathaydes
Copy link
Owner Author

I have concerns about generics... it's not good enough to bind only to things of the exact same type. This becomes really painful in real use-cases (CeylonFX presented some already).

This would be impossible, I believe, to address at the language level. If you can do that, it would be awesome though!

I have finally come up with a design for properties binding which I believe is good.

Please check it out in this gist:
https://gist.github.com/renatoathaydes/7794202

In summary:

shared class GenericSomething() {
    shared Writable<Object> anObjectProperty = ObjectProperty<Object>("");
}

ObjectProperty<String> strProperty = ObjectProperty("hi");
ObjectProperty<Boolean> boolProperty = ObjectProperty(true);

// need to wrap the function to allow covariance/contravariance (functions have fixed types)
value onlyNatIsRight = asConverter((String s) => s.equals("Natallia"));

value genericSomething = GenericSomething();

// can bind to anything as long as you have a converter
genericSomething.anObjectProperty.bindTo(strProperty, onlyNatIsRight);
genericSomething.anObjectProperty.bindTo(boolProperty, identity<Object>());

@renatoathaydes
Copy link
Owner Author

Would it be possible to add something to Ceylon to allow custom things similar to this:

// inside Property
{ ...
    shared check(isBound()==false) void set(Prop prop) { ... }

    shared Boolean isBound() { ... }
}

// then, this does not compile, you must check first if boundProperty is already bound!
boundProperty.set("value");

// this should work
if (boundProperty.isBound() == false) {
   boundProperty.set("value");
}

You could even use this to do some really cool stuff:

shared check(n > 0) Integer factorial(Integer n) { ... }

Just a late-night idea :)

@lucaswerkmeister
Copy link

@renatoathaydes, concerning check: correct me if I’m wrong, that’s basically compile-time assertions, right?
Or is there any difference between

shared check(isBound()==false) void set(Prop prop) { ... }

and

shared void set(Prop prop) {
    assert (!isBound());
    // ...
}

that I missed, other than when it’s checked?

And if I understood this correctly, what does the compiler do if I write

factorial(Random().nextInt(10));

?

@gavinking
Copy link
Collaborator

it's not good enough to bind only to things of the exact same type

Well the point is that the type of @text would be something like String(String=), so anything with that type could be bound to text. It doesn't have to be a reference to a value, it could be a chain of type converters or whatever.

This would be impossible, I believe, to address at the language level. If you can do that, it would be awesome though!

It seems to me that it can be done easily enough.

@gavinking
Copy link
Collaborator

@renatoathaydes btw, now you're starting to get into the area of type systems with dependent typing, which goes pretty deep, and is still an active area of research.

@lucaswerkmeister
Copy link

Forgive me the stupid question, but what does the type String(String=) mean? I don’t think I’ve seen it before. The compiler seems to accept it (the IDE helpfully says it’s a String(String=)), but I can’t find anything (except nothing) to assign to it (the "test".@uppercased syntax from the issue you referenced doesn’t compile).

@gavinking
Copy link
Collaborator

Forgive me the stupid question, but what does the type String(String=) mean?

It means Callable<String,[]|[String]>. It's the type of a function with a defaulted parameter like:

String fun(String arg="") => ... ;

the "test".@uppercased syntax from the issue you referenced doesn’t compile

Right that syntax is just a proposal.

@renatoathaydes
Copy link
Owner Author

@lucaswerkmeister said: correct me if I’m wrong, that’s basically compile-time assertions, right?

I'm just throwing an idea out there... I think it's possible and would look similar to Ceylon's existing mechanisms for type-checking and existence (null check), D seems to have something similar (but checked only at run time, unfortunately): http://dlang.org/dbc.html

In your example, if you write

factorial(Random().nextInt(10));

You would get a compile error (unless nextInt(Integer) were declared with the same check n > 0 as well).

To compile, yiou would need one of these, for example:

value n = 10;
factorial(n);
Integer noCheckFactorial(Integer n) {
    if (n > 0) { return factorial(n); } else { throw; }
}

@renatoathaydes
Copy link
Owner Author

I have commited code that I think works quite nicely.

Examples

Bind two properties of the same type:

bind(checkBox1.selectedProperty, checkBox2.selectedProperty);

Bind 2 properties of different types:

bindConverting(checkBox.selectedProperty, checkBox.textFillProperty,
        (Boolean sel) => sel then black else yellow);

Both methods above also have a bi-directional option:

bindBidirectional(checkBox1.selectedProperty, checkBox2.selectedProperty);

Create a Binding in the declaration of a Node:

Scene {
    fill = Binding(checkBox.selectedProperty -> ((Boolean sel) => sel then white else black));
    checkBox
};

@gavinking
Copy link
Collaborator

@renatoathaydes I want to see a real example :-)

@renatoathaydes
Copy link
Owner Author

@gavinking
Copy link
Collaborator

OK, thanks, looks reasonable at first blush. I'll try to take a closer look tomorrow.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants