Skip to main content

JavaFX binding is neat, but ... beware

Posted by fabriziogiudici on June 11, 2009 at 2:45 PM PDT

An interesting chains of discussions has been triggered about JavaFX features and how it can be possibly used beyond the GUI scope.

Osvaldo has just published an interesting post. Actually I like binding a lot, but I was wondering about some adverse effects that can arise out of binding use.

There is a basic conceptual problem: binding is an evolution of getters/setters, that is exposure of naked properties. According to OO principles it is a breakage of information hiding, that should implemented by encapsulation, but we got used of it because of fourteen years of Java, as most of the Java frameworks use it (not only Swing, but also JPA etc...). So we can live with it - but I'd say I'm fine with it for some mundane uses such as populating a UI or a persistence bean; it would be probably better if we learned to avoid it for core business classes.

Anyway, this is just a general premise; now let's consider a specific example. Consider the following JavaFX class:

class Breakable
    public var theProperty = 0;

    public function breakIt(): Void
        theProperty = 4;
It's fine, right? You can even unit test it without problems, so you declare it stable.  Now, you use Breakable in this context:

var breaker = 1;

def breakable = Breakable
    theProperty: bind breaker;

public function run(): Void

Run it, and you get a

com.sun.javafx.runtime.AssignToBoundException: Cannot assign to bound variable

You can't execute theProperty = 4, since theProperty is bound and, by definition, at every moment can only hold the same value as breaker.

Do you see my point? An external class has broken Breakable, that was fine by itself. We have injected a problem. This is a worse breakage than breaking information hiding in Java by getters/setters, as not only we can change the internal status of Breakable (forgivable as explained in the premise), but we changed also the behaviour of theProperty, that now can't be assigned any longer; it is now incompatible with the original behaviour of Breakable.

I'd be worried about using this in a core business class. OO exists to make our software more robust, but binding in this perspective can make it more brittle.

I propose to address this issue by introducing an unbindable keyword such as:

class Breakable
    public unbindable var theProperty = 0;

    public function breakIt(): Void
        theProperty = 4;

This would make the compiler stop with an error when you try to bind theProperty (the problem is unidirectional binding; bidirectional binding is ok). You might think that the enhancement of the compiler could be done without a specific modifier, as the compiler could induce the unbindable status of theProperty by just finding the assignment theProperty = 4; but this is just a simple example, and theProperty could be a protected variable manipulated by a subclass.

This small example can be checked out as a NetBeans project from:

svn co -r 45


Also, I would imagine there would be some kind of restrictions on what kind of code is allowed in a validate block so as not to circumvent the constraints.

With regard to validating, vetoing changes, this also has been discussed on the JFX mailing, and the consensus back then was leaning toward adding true "full-blown properties" support to the language, which would support such functionality (i.e. validation phase first, followed by mutation phase). As to when, I don't know. Anyway below is a snippet of that discussion that I could track down: Brian Goetz wrote: > I agree that attribute validation is an important element of creating robust components. > > Having triggers throw exceptions / silently reject modifications is not going to work, though, because it could leave the application in an inconsistent state. > > There are two approaches we've discussed for attribute validation: first-class properties, and declarative constraints. But both suffer from the problem that modifications can come at the end of a chain of bindings or trigger updates, and simply rejecting them would leave things in an inconsistent state. To really make this work, transactions are needed -- there needs to be a way to reject (and roll back) the entire chain of modifications that caused the update. I agree having some way of defining at least simple constraints is nice. However, I think you need to have either full-blown properties, or at least something comparable. For example, in this case I want to clip the values < 0 to 0, and > 1 to 1. It is more than a constraint; it is logic that I want executed prior to attribute mutation, and have it possibly change the value finally set on the attribute. Transactions are an interesting idea. I think what you don't want is to update values twice. So if variables a, b, and c are updated whenever x changes, you don't want to update a and b, find out with c that there is an error, and then reset a and b to their prior values. The problem being that there could be side-effects in triggers based on mutating the state. This would suggest that the validation phase should be separate from the mutation phase, and prior to it. So you would validate with each binding target that the new value would pass any and all constraints/validation, and then set all the values. Richard

@opinali: I'm mostly happy that I will be able to run 6 on my 32-bit Intel machine, which I couldn't do in Leopard.

@cloj, @fabriziogiudici: The 32/64 choice seems good, but is this really necessary in a post-JDK 6u14 world? As soon as Apple catches up to that release (or better), they could use the Compressed References optimization, which delivers similar performance (both speed and memory usage) to a 32-bit VM, but without the disadvantages of not running in the same process model that is preferred on a 64-bit OS.

@felipegaucho: I agree that 99% of all JS code out there stinks... but this phenomenon has several causes, including coders that don't really get JS (which draws more from Scheme than from C-family langs), and its long role as a language for tiny web 1.0 scripts (simple event handlers or validators etc.) so people got used to hack code in text or HTML editors without worrying about good programming practices or even asking for proper tools. So, I don't see the connection to JavaFX, other than the very superficial "both were created for GUIs but will expand to other tasks". Any language or tool can be abused. I remember when JSP 1.0 was in beta and I adopted it for a big web project... this resulted in a monstrous codebase with some JSPs having thousands of lines due to scriptlets; that was the "recommended" way of doing JSP before we had taglibs and other improvements. (Thanks god that application is not in production anymore, I'd rather change my name and disappear than maintain it.) In this case, it's the Java language that was abused as a web scripting language.

A bit of a surprise. Thanks for pointing out, I'll eventually blog about it.

Hey Fabrizio, you may be interested in (snow leopard has 32-bit java 6).

@Osvaldo: "And I didn't understand your comparison with JavaScript.." well, javascript was created in the pre-historic era of Netscape to solve simple GUI problems.. to add dynamic content to HTML static pages.. well done... it was good enough for that .. and then AJAX came, and Embedded DB, and soon people started to ask : "why I need a server or a power backend if I can do wonderfulness in my browser".. and then you have the twenty thousand lines javascript unmantainable crap out there.. a wonder of how low a human kind can go.. :) of corse I am a bit sarcastic today since I am cleaning another script here.. but in my oppinion, a extremely power GUI language is much more what is missed in the Java platform than another script simulating server in the browser.. or in a phone, whatever :) layers separation can be overused, or not.. and I know people will try to do everything with JavaFX some day.. But for now, let's try to have some productivity with that first to think about how we can misuse it :)

@fabriziogiudici: It's easy to produce a StackOverflow with indirect recurson, like this: var i = 0 on replace old { i = 5; } var j = bind f(i); function f(x) { ++i; } Now this is pretty stupid code, but we both may have written code that did something similar... the JavaFX runtime will not check if a activation of the var's trigger is already active, to avoid recursion of the trigger (that would be a possible, but expensive check, requiring either a stack walk or some per-trigger "running" flag... better not doing that, triggers and binding are already expensive enough).

@felipegaucho: Any successful language will inevitably expand its reach to domains it was never intended for. Just look this: (people promoting Python as a replacement for Fortran, for scientific stuff... although Python is up to 300X slower than Fortran: Let's just assume that JavaFX becomes a very successful RIA platform, OK? This means thousands of trained developers, libraries, tools, books, etc. And JavaFX Script is not 300X slower than Java; in fact it is very often just as fast. Why not enjoying a more productive, expressive language for your non-GUI code, if you already know and like that language? And I didn't understand your comparison with JavaScript... could you be more specific, or that was just part of the trolling? ;-)

So... what the f**k were those stack overflows that I saw too? :-/

@diverson: That's odd, I was pretty sure that a self-assignment inside the trigger (at least w/o a conditional guard) would result in recursive call of the trigger. That's because I actually experienced a stack overflow involving that. But this was some time ago and probably involving other factors, like binding. I tested again on JavaFX 1.0, 1.1.1 and 1.2 and they all behaved well without recursive calls. This is good news. OTOH, the interaction with binding, causing listener expressions to see the invalid results before rollback, is important like Fabrizio points. In theory I can avoid any trouble by having only purely functional code (side-effect free) in bound expressions; but that's a workaround (at best a good practice), not a full solution for the problem.

as presentation layer, JavaFX has a chance.. .small but has one.. as mixed up solution business+presentation+persistence all-crap-old-javascript-style, I prefer to quit JavaFX for this life :) eheh serious, JavaFX is already so questionable technology and so hard to sell out there, if we start to repeat the errors from javascript we are just eating the elefant again :( we don't need that :) IMHO

"But note that any bound variable will see the invalid change as well as the roll back." Which is not the same as vetoing a change: you have the invalid value go everywhere, potentially causing harms. For what concerns sequences, the compiler can do the perfect optimization, but the point doesn't change, you can't change semantics. You can mix Java code and use whatever you like, but you're forced to completely change the way you manipulate the object (i.e. square brackets vs get(i)) and your client code gets affected by the change. No, I tried a few times to improve the formatting of code samples in comments, but I don't think it's possible and I gave up. Thanks for pointing to that discussion on the mailing list. Indeed, Richard's comment: "Yes, this is a big problem from my perspective as I have to basically wrap all "sets" to public variables in try/catch blocks because the user may have bound one of them." is very good, as it demonstrates that in order to design robust code you have to pollute it with a lot of try / catch, jeopardizing the compactness of the language. BTW, I don't see the isBound() as a good solution: you have to replace try / catch with if, but the code pollution is still here. Furthermore, I'm again with a conceptual point: if you're assigning that variable in your code, that's incompatible with unidirectional binding, that's a design thing, you've not designed it with binding in mind. I'd really like I could declare it to the compiler, so I can enforce the prohibition of binding.

Interestingly enough, this particular issue has been discussed on the JFX-Compiler mailing list a while back. Below is a snippet of that discussion. I wonder what the final resolution were. I also wonder whether the compiler can be made smart to detect such conflicts (i.e by detecting assignments) at compile time and flag an error, rather than getting a runtime exception. Which in my view would the better option since it spares us all these runtime checks. --- On Wed, 3/4/09, Brian Goetz wrote: More precisely, what you want is isAssignable(). On Mar 4, 2009, at 6:59 AM, Richard Bair wrote: > I think in this case what I want is a isBound function so I can check whether a var is bound before I try to set it. > > > > On Mar 3, 2009, at 4:15 PM, Robert Field wrote: > >> OK, my question is, after initialization, do you ever want the user to be able to set this? >> >> If not, the 'public-init' is the access modifier that you want. 'public-init' does not allow bind. >> >> We certainly discussed general access modifiers that prohibited bind, but we reasoned that if this is a variable which is controlled by the class (set at its whim) then it is probably not going to be one that the class wants randomly externally set. >> >> Even if you do want it externally set, this could still be done with 'public-init' and a setter method, though admittedly this isn't the most elegant solution. >> >> -Robert >> >> >> Richard Bair wrote: >>> Yes, this is a big problem from my perspective as I have to basically wrap all "sets" to public variables in try/catch blocks because the user may have bound one of them. >>> >>> On Mar 2, 2009, at 2:17 PM, Michael Heinrichs wrote: >>> >>>> Hmmm, it looks like my original intent got lost in this discussion. The attributes stage.width and stage.height were meant as examples to demonstrate this is a real life issue. >>>> >>>> The question is, how can a user determine, if a public variable can be bound. The documentation does not provide enough information right now. So the only way at present seems to be to try it and see if one gets a runtime exception. >>>> >>>> This gets even worse, if we have a public variable, which is only rarely changed by the runtime. If a user binds this variable it would usually work, but throw an exception in these rare cases. >>>> >>>> Michael

opinali: Maybe I'm misunderstanding your problem, but you can assign an old value back to a variable in a replace trigger without causing a stack overflow. class A { var aVar = 0 on replace oldValue { println( "aVar being set to {aVar}" ); if (aVar < 0) { aVar = oldValue; } } } var aRef = A { aVar: -1 } def boundAVar = bind aRef.aVar on replace { println( "boundAVar being set to {boundAVar}" ); } aRef.aVar = 3; aRef.aVar = -2; println( "aVar is {aRef.aVar}" ); Results in the following output: aVar being set to -1 aVar being set to 0 boundAVar being set to 0 boundAVar being set to 3 aVar being set to 3 boundAVar being set to -2 aVar being set to -2 boundAVar being set to 3 aVar being set to 3 aVar is 3 It doesn't allow you to approve the change before it's made, but you can roll it back. But note that any bound variable will see the invalid change as well as the roll back. p.s. Anyone know how to preserve code indenting in these comments?

Overriding [] would be cool, but the sequence type is parte of the language, it's not APIs. This is a common tradeoff of most (all?) languages that have built-in high level types, since LISP with its lists, is that you don't muck with such types... comapring JavaFX Script's sequences with Java's similiar List Collections, you cannot pick a specific implementation (e.g. array or linked), or specify creation-time tuning like initial size, you can't define your own variant etc. But it's a tradeoff, as javafxc does a very respectable amount of automatic optimizations and that's only going to improve.

Yes, this is another problem, as you can't enforce the feasible values for a variable. More generically (subject for another post), a lot of things in JavaFX occur behind the scenes, and there's not a method that can be made polymorphic. For instance, the square bracket operator of sequences is neat for a compact syntax, but you can't override it, thus you can't have lazy-loaded sequences etc...

Agree with mikeazzi... except that JavaFX Script's triggers don't allow me to validate and veto changes. I would want to write something like that: var age on replace { if (age &lt 0) // ... some code that blocks the requested assignment } Right now, triggers are invoked after the assignment was already performed. and you can't assign the old value back because this results in a StackOverflow as the trigger is invoked recursively. You can throw some exception, invalidate the object..., but that's not as good as blocking invalid assignments. I guess I'll look at the JIRA and make a RFE for this if there's none yet. One idea for concrete syntax: var age on before replace newAge { if (newAge >= 0) age = newAge; } I'm reusing the before keyword, and changing semantics: (a) the assignment made by triggering code doesn't assign a new value, only invokes the trigger; (b) the newValue parameter is mandatory (similar to the optional parameter for old values in normal triggers); (c) assigning a value to the var inside that trigger will be a raw assignment, without invoking the trigger again.

Information hiding has only to do with private, and possibly protected. Anything that is public breaks information hiding (including public-read). Anyway, this is just a picky observation ;-) the point is that none of the existing JavaFX access modifiers help me: in this example, I want theProperty to be publicly readable *and* writable; it's just that breakIt() can write on its own, too (think of theProperty as a counter that you can read and write, and breakIt() is a reset() method). Note that I wouldn't have this problem in Java: I'd only need to take care, in the setter method, if some special processing must be done whenever theProperty changes value. The difference is that JavaFX binding enforces the binding behaviour, while BeansBinding in Java doesn't (you can assign a "bound" property, thus breaking the binding). I'd say that it's the right decision for JavaFX, because of its functional nature; but it introduces the new problem I'm talking of. Of course, one could argue that this is bad design, and I might agree - but, at this point, I say that using "public" is the root of the problem, and JavaFX binding favours a lot the use of public variables, much more than Java.

Yeah, but I am sure you are aware of JavaFX access modifiers: public, public-read, etc. These modifiers are JavaFX's version of information hiding. So I don't think JavafX is breaking this OO principle per se if proper use of these modifiers is being applied. So in your particular case if internal functions perform writes on a certain variable then it should be made public-read for instance. Unless I am missing something.

It wulld be great to have a replace trigger "before replace" and a "cancel replace;" when some codel (ex.validation of the new value) fails or just to attach a block of code thet return a boolean result indicating to continue the "replace"

@mikeazzi: The whole problem is indeed difficult, but "the perfect is enemy of the good". If I can just veto changes to a single object without any side effects (no listeners notified of the change before it's vetoed), at least I don't let any object enter a corrupt internal state... I can still have a bad state in a graph of dependent objects because object A was changed and dependent object B was not changed as expected by the A-B binding (that we can see as a kind of contract); but this is certainly a less severe case of corruption, and in really important cases (e.g. if A and B are part of some security-sensitive API) there are always workarounds like A invoking a validation method of B before A accepts the change. The separate validate block would be a good idea, solving the problem above, I agree that the system must trust the programmer to have only side effect free code in the validation blocks but that would be a perfectly fine compromise... lint tools could enforce this if javafxc wouldn't (as detection of functional purness would be a bigger RFE to javafxc at this time - but a good idea in the long run; JavaFX Script has very good potential to evolve its functional side, but that's another debate).