#321 Slot literals

jodastephen Sat 26 Jul 2008

Breaking out new discussion from here.

Slot literals are something I brought to the Java closures debate with FCM.

There, I used the # symbol to represent a compile-time checked way to access program elements (constructors, methods and fields in Java), plus a way to bind those elements to objects.

The FCM Java proposal is:

Person#surname              // the surname Field on Person
Person#setSurname(String)   // the setSurname Method on Person
Person#(String,int)         // the Constructor on Person

person#surname              // binds the Field and the person object
person#setSurname(String)   // binds the Method and the person object

Thanks to the single slot names in Fan, this can be simpler:

Person#surname   // the matching slot (Method or Field)
person#surname   // binds the slot and the person object

This approach covers the basic concepts, and I'd recommend providing both forms (slot literal and binding to object).

However there are two other things to consider - constructors and types. If constructors remain as psuedo factory methods with an actual name (make) then that problem is solved:

Person#make      // the constructor Method

Type literals could be a natural extension to this:

// currently
Person.type
// possible alternative
Person#

which leads to syntax such as this:

// currently
facet := Person.type.facet("facetName")
// possible alternative
facet := Person#.facet("facetName")

I'm not sure I like the #. combination, but it is a consistent logical extension of the use of #.

brian Sun 27 Jul 2008

I was thinking about the Type# syntax also - it is the obvious way to unify the two concepts. But I don't really like the suffix symbol.

I think the problem is that anything we do such as Type<symbol>slot for slot literal will logically follow that Type<symbol> is the type literal.

I was also thinking about some type of prefix symbol:

#Str
#Str.replace

But that doesn't work well for calling methods on the type literal:

#Person.facet("facetName")    // wrong
(#Person).facet("facetName")  // ok

brian Tue 29 Jul 2008

There hasn't been much discussion about slot literals? This is something I think Fan really needs, and since it is likely to change the syntax of type literals, I want to do it soon.

After some more thought I think using # as a prefix might work best, that way you can do type literals as well as qualified and unqualified slot literals:

#sys::Str     =>  Type.find("sys::Str")
#Str          =>  Type.find("sys::Str")
#Str#replace  =>  Slot.findMethod("sys::Str.replace")
#echo         =>  Slot.findMethod("sys::Obj.echo")

I don't really love the syntax, but it solves all the cases consistently. It also lets you use a dot operator after either a type or slot literal without any trouble:

#Str.qname
#echo.params

Comments about this proposal? Alternate suggestions?

JohnDG Tue 29 Jul 2008

Agreed it's hugely needed. No real preference on a syntax (as long as it is consistent everywhere).

jodastephen Tue 29 Jul 2008

I agree with the "we need this". This proposal (# at start) actually looks quite good.

A question though. How does the compiler disambiguate #echo from #echo, where the first is a slot name, and the second is a class name?

tompalmer Wed 30 Jul 2008

Here are my opinions:

  1. Also agree that it's very good.
  2. #slot is the right syntax.
  3. Type# (not #Type) is the right syntax.

The # syntax mirrors link anchors in URIs. It's beautiful that way really (which is why it's sad that it's also my favorite comment char, but happily y'all already have that out of the way by going //).

Anyway, just like document.html# generally goes to the top of the page, Type# should refer to the "top" of the entity/type or rather, the type itself.

brian Wed 30 Jul 2008

So Tom you are proposing that type literals use a suffix and slot literals use a prefix? I think that works fine too:

sys::Str#     =>  Type.find("sys::Str")
Str#          =>  Type.find("sys::Str")
Str#replace   =>  Slot.findMethod("sys::Str.replace")
#echo         =>  Slot.findMethod("sys::Obj.echo")

// with dot operator
Str#.qname
#echo.params

Cast your vote between the two:

  1. Using prefix only: #Str, #Str#replace, #replace
  2. Suffix on type, prefix on slot: Str#, Str#replace, #replace

JohnDG Wed 30 Jul 2008

The anchor mechanism is a nice way to understand it (nice idea, Tom). So I think I prefer B.

tompalmer Wed 30 Jul 2008

Brian, that is indeed my proposal (matching Stephen's original one up top -- I just added an explanation of why I like it).

jodastephen Wed 30 Jul 2008

I think A is ambiguous wrt class name vs slot name, so I have to choose B.

brian Wed 30 Jul 2008

Ok, I will consider this design finalized. Some other examples to consider also:

Int[]#
Str:Obj#
|Int a, Int b->Int|#

The formal grammar will be changed such:

<typeLiteral>  := <type> "#"
<slotLiteral>  := [<type>] "#" <id>

brian Wed 30 Jul 2008

Just to be clear, the Type# syntax is going to replace the Type.type syntax (I'm not keeping the old syntax to let you choose one or the other).

jodastephen Wed 30 Jul 2008

I'm happy with what you have proposed, but I thought I'd add a few more comments:

1) What does a # on its own mean? Perhaps it means "the surrounding class", which is a useful extra feature:

static Void makeFoo() {
  #.make("Foo")
}
static Void make(Str str) { ... }

This is contrived example obviously, as you could just call make directly. But this problem has come up in Java quite a bit, especially with testing and logging frameworks.

<typeLiteral>  := [<type>] "#"
<slotLiteral>  := [<type>] "#" <id>

2) Here is an alternate syntax:

#Str#
#Int[]#
#Str:Obj#
#|Int a, Int b->Int|#
#Str#echo
#echo

<typeLiteral>  := [#<type>] "#"
<slotLiteral>  := [#<type>] "#" <id>

I think I prefer the double #, as it reads a little bit like brackets.

3) Is there any way to remove the type slot name from ordinary objects? With the double # I believe there is:

obj#

This is especially useful as "type" is a common noun that many, many business classes are going to want to use as a slot themselves.

brian Wed 30 Jul 2008

I think the # as meaning type of enclosing class might be nice. I agree that in Java when you need that in a static context it is a pain.

I don't really like the bracketed # syntax and I don't think it is as consistent with slot literals since they aren't bracketed.

I think what you are suggesting for Obj.type is an operator via # versus a virtual method. I'm not sure I like that. Plus one of the original points of the discussion was that type literals and typeof should have different syntax.

jodastephen Wed 30 Jul 2008

I can live with the trailing # for types, but I don't find it as readable.

Thread.findService(FooBar#)

Thread.findService(#FooBar#)

I find the second jumps out more clearly.

On point (3), yes I am suggesting replacing the Obj.type slot. I really, really don't like typing up a business level concept like "type". When Java ties up "class" its bad enough (eg. HTML/CSS), but probably over 50% of my business model classes have a getType() of some form.

brian Wed 30 Jul 2008

I'm working on this feature right now. I wasn't that fond of the Type# syntax, but actually it is growing on me really quick. You use type literals a lot in tests:

// old way
verifyErr(IOErr.type) |,| { ... }

// new way
verifyErr(IOErr#) |,| { ... }

Its only taken me a little time to start preferring the latter syntax.

brian Wed 30 Jul 2008

I really, really don't like typing up a business level concept like "type".

I am open to that debate, although remember we actually have to provide some Java and C# API to get to this method too for native code. So unless you make that method something like type$ then we're going to have naming collisions.

jodastephen Wed 30 Jul 2008

The type$ would seem like a fine workaroud. After all you must face the same problem with a Fan method named getClass.

BTW, why don't you give #Str# a try whle you're coding the feature? You just might like that even more ;-)

brian Thu 31 Jul 2008

BTW, why don't you give #Str# a try whle you're coding the feature? You just might like that even more ;-)

Actually I tried it out a bunch of places when you suggested it. It isn't bad - but not sure I like it as much as Type#. At this point but I think anything we pick is just something that you're going to have to get used to since any syntax will be a bit foreign.

The type$ would seem like a fine workaroud. After all you must face the same problem with a Fan method named getClass.

Let's start another thread for this discussion and see what everyone has to say. This is much more involved breaking change.

andy Thu 18 Sep 2008

I've been using the type literal a lot with fwt recently, and found it would be very nice if a lone # meant my surrounding class as Stephen proposed:

class Foo {
  Void foo() {  
    echo(#.name)  //  -> Foo
  }
}

My most common case has been:

cmd := Command.makeLocale(#.pod, "myCmd", &onCmd)

So I propose this gets added.

katox Fri 19 Sep 2008

I'm a bit discomforted by that many metacharacters in Fan. I know they save typing but readability suffers. Where does the # symbol for types come from? Have you considered syntax alternatives? Maybe longer but more alphabetical?

Curiously #.name syntax looks quite ok unlike someObject#method which is very thick and unreadable. It also, sort of, replaces finder methods -- I have no association of # and finders either. I can think of shell comments, C includes and velocity templates (yuck!).

Sure, this is very subjective. But to me it is as ugly as C# bracket annotations...

tompalmer Fri 19 Sep 2008

I've mostly been gone for a while, and I think I'll still mostly be gone. (Busier than expected.) But I agree that # for surrounding class would rock. Another important use case is #.log.

Where does the # symbol for types come from?

From URIs, effectively. And just like # inside an HTML document refers to the top of the document, I think it makes sense here by itself to refer to the surrounding class. It's not 100% the same, but I think it's close enough to remember the meaning.

brian Sat 20 Sep 2008

Hey Tom - haven't seen you around here lately - we've been missing you :)

I agree with Andy, after some intensive coding on Flux this seems to come up all the time - the need to reference your enclosing type in a static context. Often you need it to get the log or the pod for localization calls. Convention seems to be moving towards using Type for this stuff:

// say I'm in the FooBar class
Command(FooBar#.pod, "i18n.key")
FooBar#.loc("i18n.key")
FooBar#.log.error("something bad")

What all these use cases have is that you have to repeat the enclosing class - kind of like Java style constructors. Its a bit ugly and non-DRY.

Stephen actually proposed something a bit more ambitious which was to use # to try and get rid of the Obj.type slot. I agree with him that taking "type" as a slot name away from application code sucks - so I definitely think we should consider that. That would entail:

  • coming up alternate method names to use in Java and C#
  • deciding how # could be used in static and instance context

Login or Signup to reply.