#682 Proper Properties in Fan?

mikaelgrev Fri 24 Jul 2009

Hello Fanboys (and gals),

I think Fan looks like a very interesting language, still, after being away for a while.

But, one of my pet peeves when it comes to a good language is the property support. Now properties are a little funny. Either you use them a lot or you don't use then at all it seems. Brian seems to be one of those who don't, or so I gather from reading some earlier posts.

Fan seems to implement properties in a very light way. They are basically public fields with some options, as far as I understand from looking at it briefly. But properties can be so much more and code looks really neat when you have everything properly contained in the properties of an object.

For properties to be powerful enough a few things need to be available (non-complete):

  • Property implementation, code that handles the incoming/outgoing value from the backing field/store, needs to be extensible. The language should come, using APIs of course, with a few (like BoundProperty, IndexedProperty and MapProperty) but you should be able to create your own. For instance TimedProperty, CachingRemoteProperty and what not.
  • Property code needs to be able to be as efficient as a normal getter/setter in Java, both CPU and memory wise. This rules out separate objects for instance since they will use more memory than a singe field. It also means that the property implementation code needs some language supported way to access the field of an object.
  • Properties need to be overridable in sub classes. Think normal getters/setters here.
  • Property code needs access to the instance annotations so they can react appropriately. Think for instance annotating a property with @Min 5 to make it validate the value.
  • Property code needs to be generics based. (btw, generics are great, but they should have had the same type system as arrays (i.e. simpler, but with possible runtime CCEs).

For further reading I wrote a proposal some time ago in hope to get this into Java, but time and lacking Sun interest has made it somewhat stale. http://migcalendar.com/properties/proposal.html

I have also implemented it in Java using value object. It works great but it would be even better if there was no need for the container object (which in Java could actually be solved with a compiler addition and a special syntax for accessing the field). The project is here if anyone is interested: https://properties.dev.java.net/source/browse/properties/trunk/

So, now on to the question I had, how likely is it that "proper properties" will be included in Fan? For me that would be the killer feature, all categories.

Cheers, Mikael Grev

tompalmer Fri 24 Jul 2009

These items are already supported by Fan properties (even though the simple syntax looks like fields):

  • Property code needs to be able to be as efficient as a normal getter/setter in Java, both CPU and memory wise.
  • Properties need to be overridable in sub classes. Think normal getters/setters here.

I'm not sure you can put facets on instances. Do you mean local var annotations in Java? Because annotations definitely aren't carried on object instances in Java, unless I'm just remembering wrong.

That said, you can definitely put facets on your property definitions and inspect them at runtime.

I'm not sure I understand the full requirements of everything on your list, so I won't comment on the rest for now.

brian Fri 24 Jul 2009

This has been discussed previously in #631, #598, #312.

I believe the current design is the right level of features for field support. It has all the mechanisms to build/override getter/setter/storage.

I agree there are some missing pieces to implement more bound property style of fields. I think that is most likely an orthogonal feature which gets combined with the existing field mechanisms.

Andy and I will likely tackle data binding for some of the FWT stuff at some point and we will look at the issue, but I don't consider it an immediate priority compared to finishing up stuff like symbols and repos.

qualidafial Fri 24 Jul 2009

Any plans to introduce a standard notification API in time for 1.0? Right now we have fwt::EventListeners but if we add bound properties later on we'll want them to use the same API to keep everything consistent. Something like C# delegates would be really great.

Text
{
  onKeyDown += |KeyEvent e| { echo("key pressed: "+e) }
}

Ideally delegates would be parameterized for compile- and run-time safety:

class Widget
{
  delegate |KeyEvent->Void| onKeyDown
}

qualidafial Fri 24 Jul 2009

Another delegate signature, with possible usage:

Person
{
  Str name
  {
    get { *text }
    set
    {
      onNameChange(*text, *text = val)
    }
  }

  delegate onNameChange(Str,Str)
}

mikaelgrev Fri 24 Jul 2009

I real solid component model need real solid properties and events and it needs it from the start so that APIs are written around it.

tompalmer Fri 24 Jul 2009

Actually delegate definitions are named function pointer types in C#, almost typedef of sorts, but maybe it uses nominal typing which I guess would make them a sort of succinct interface. Anyway, I think you are really talking about the C# event keyword.

I'm not sure C# events are the right way to do things. Seems like language bloat for a very specific use case, but maybe I haven't programmed that way enough to know why I'd want them like that.

I'm much more interested in Flex/JavaFX-style data binding, though I also haven't used that too much, at least not outside spreadsheets, but I tend to think it's because such features don't exist in languages that I've used. I do agree that adding this feature (or whatever related language features) later could risk making a lot of APIs instantly outdated.

tompalmer Sat 25 Jul 2009

It occurred to me they probably had events in C# 1.0 because they didn't have generics yet but still wanted typed callback lists without making custom containers (and also didn't want to use standard arrays). Looking back I see, qualidafial, that this was your context in the first place. My apologies on not thinking through it better.

I guess you could expose a full List of some function type in Fan. Might work, but without events on the list itself, and without List being customizable, it would be hard to control what happened as the list changed. So the convenient technique wouldn't fit every use case.

Note that I'm still speaking in the abstract and not about fwt specifically, since I'm still mostly unfamiliar with it.

qualidafial Sat 25 Jul 2009

If I understand correct, C# delegates (events) are just syntactic sugar for a hidden listener-list object like fwt::EventListeners. So the code:

text.onMouseDown.add |Event e| { echo(e) }

is little different than:

text.onMouseDown += |Event e| { echo(e) }

usage-wise or architecture-wise. However in the former example (using EventListeners) you have no compile-time or even runtime type safety, you just find out that you added an event listener of the wrong type when the program blows up. With true delegates (the latter example) you get compile-time type safety--you cannot pass in a function that doesn't match. I'm thinking in terms of different events having different listener signatures here, whereas EventListeners only guarantees the signature |fwt::Event|.

Plus with delegates you get to call the delegate just like a Func object and it parlays that call to all added listeners:

text.onMouseDown.add |Event e| { echo("foo") }
text.onMouseDown.add |Event e| { echo("bar") }

// In reaction to a mouse-down event:
onMouseDown(Event()) => foo
                        bar

This would be a non-issue if we had generics. I know, I know--I'm just saying.

tompalmer Sat 25 Jul 2009

In C#, delegates are typesafe function pointers. Events are (sort of) lists of delegates that dispatch to the added delegates, using something like the composite pattern.

In Fan, you could potentially have onMouseDown be a |TextEvent->Void|[] (or whatever), is what I was saying. Not that it would all work out ideally (depending on whether you wanted standard List behavior). I was just mentioning the relationship between this and C# events.

qualidafial Sat 25 Jul 2009

@tompalmer: Ok, thanks for the clarification, I was a little mixed up there. I read up on C# a couple years ago but it's been a while.

qualidafial Sat 25 Jul 2009

Would be nice if this#methodName evaluated to This#methodName.func.curry(this) for convenience.

brian Sun 26 Jul 2009

Would be nice if this#methodName evaluated to This#methodName.func.curry(this) for convenience.

You can do that today with the & operator:

&this.method

It is convenient, but I wonder if just having closures isn't enough.

qualidafial Mon 27 Jul 2009

You can do that today with the & operator

<facepalm/> I forgot about that, thanks.

Next question, can a field be curried e.g. &this.field? If yes, does the Func behave as a getter or setter depending on the number of arguments (0 or 1, respectively)? And if yes to that, would passing a single null value cause the Func to behave as a setter or as a getter? I ask because I'm looking at the Func.call method with its eight optional arguments all defaulting to null--and since you can pass in null manually I wondered if that could possibly screw up the application of optional parameters.

tompalmer Mon 27 Jul 2009

I wonder if just having closures isn't enough.

I've wondered similar things sometimes, especially if it-blocks were allowed generally. Then &method would just be {method}, right? And even |,| {method} isn't too bad.

Further, function expressions are more general than currying, since you can fill any params you want: |Int a| {method(a, 5)} or whatever.

Next question, can a field be curried e.g. &this.field?

I'm personally feeling biased at the moment towards eliminating & or perhaps repurposing it for instance-bound fields. That is, if this#field isn't attached to this, then maybe &this.field (including plain &field) or this.&field could be. And if this were done, I'd be afraid of confusion caused by allowing it to reference non-field methods. I'd require that it be a read-write field.

tompalmer Mon 27 Jul 2009

Oh, and a ping on orphaned it-blocks and general-purpose closure type inference, since I mentioned it above. And note my usage above for the orphaned it-block matches JohnDG's requested semantics (rather than my alternative that I brought up in that thread).

brian Mon 27 Jul 2009

no - I do not allow curried fields at the moment

... and to echo Tom, I am kind of thinking that we should consider removing the curry operator completely in favor of just using closures. seems as reasonable simplification (I added it 2 years ago, but found I don't actually use it that much).

tcolar Mon 27 Jul 2009

Agree with tom too.

qualidafial Tue 28 Jul 2009

... and to echo Tom, I am kind of thinking that we should consider removing the curry operator completely in favor of just using closures.

What about partial application of arguments?

brian Tue 28 Jul 2009

What about partial application of arguments?

The curry operator lets you partially apply zero or more arguments from left to right (where implicit this is always left-most). Closures let you partially whatever arguments you want (in whatever order).

andy Tue 28 Jul 2009

I'm on board with removing the curry operator. Would rather use & for the field storage over * - then again, probably better to keep it free for now.

Login or Signup to reply.