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

syntax for qualified types #3516

Closed CeylonMigrationBot closed 8 years ago

CeylonMigrationBot commented 12 years ago

[@gavinking] Belatedly, I've noticed a potential inconsistency in the syntax for qualified types and metamodel references.

In principal, if we defined the metamodel type Class to have a member type, Iterator, for example, then the following phenomenon would occur:

This is not an actual ambiguity as such, but it's certainly undesirable. Of course, it's a phenomenon that will never occur in practice, if we simply don't define any member classes of the metamodel types.

A second related observation is that with the introduction of the syntax Iterable::Iterator in #3509 we have gained a second redundant way to express a qualified type. This is also undesirable, I believe.

There's three ways to handle this that I can see:

  1. Do nothing: this is certainly a wrinkle, but since we're the only ones defining the metamodel, we can make sure it never manifests in practice. Java (and C#) developers are used to writing Iterable.Iterator, and . is much easier on the eyes than :: or @. It's not especially strange that type-level operators have slightly different semantics to value-level operators—just look at | and &. Hell, we didn't even notice this wrinkle until now, so the chance of anyone else actually noticing it is somewhere in the range -1p..+1p.
  2. Use :: for qualifying types: we now have a totally reasonable and unambiguous syntax for writing qualified types. The semantics of #3509's Foo::Bar is a simply much better and more natural fit here than the semantics of .. We're be adopting a really strained second interpretation of ., just because we think it looks slightly prettier, and because we're used to it. Why have two totally synonymous ways to qualify a type name?
  3. Always qualify metamodel references with @: we already need that for attribute references. Why not force you to write, for example @Iterator.Iterable(), making it completely unambiguous that you're talking about the metamodel here. Then Iterator.Iterable could mean exactly the same thing wherever it appears.

I'm quite uncertain which option I prefer. Option 2, perhaps.

[Migrated from ceylon/ceylon-spec#410] [Closed at 2013-01-04 15:04:57]

CeylonMigrationBot commented 11 years ago

[@quintesse] Well I meant to use them only when necessary, so you keep @Person but add @<Integer|Float>

CeylonMigrationBot commented 11 years ago

[@gavinking] well that doesn't really fit into the scheme I outlined above. How would you handle Map.Entry.key?

Sent from my iPhone

On 15/05/2013, at 12:38 PM, Tako Schotanus notifications@github.com wrote:

Well I meant to use them only when necessary, so you keep @Person but add @<Integer|Float>

— Reply to this email directly or view it on GitHub.

CeylonMigrationBot commented 11 years ago

[@gavinking] and stuff like String|Map.Entry?

Sent from my iPhone

On 15/05/2013, at 12:38 PM, Tako Schotanus notifications@github.com wrote:

Well I meant to use them only when necessary, so you keep @Person but add @<Integer|Float>

— Reply to this email directly or view it on GitHub.

CeylonMigrationBot commented 11 years ago

[@quintesse] Well couldn't you still do the following?

@<String|Map.Entry>

Or combine the suggestions?

@`String|Map.Entry`

That way you keep the short version for many cases and only use the grouping when necessary. I suggested the < > only because it's already used with type grouping, but of course in this case it's not only used with types (as seen with Map.Entry.key), so maybe we could use @ and @( ) and not have to use the last free symbol we have :)

CeylonMigrationBot commented 11 years ago

[@gavinking] The two approaches are quite different. I don't see how they mix, except confusingly.

Sent from my iPhone

On 15/05/2013, at 1:22 PM, Tako Schotanus notifications@github.com wrote:

Well couldn't you still do the following?

@<String|Map.Entry> Or combine the suggestions?

@String|Map.Entry That way you keep the short version for many cases and only use the grouping when necessary. I suggested the < > only because it's already used with type grouping, but of course in this case it's not only used with types (as seen with Map.Entry.key), so maybe we could use @ and @( ) and not have to use the last free symbol we have :)

— Reply to this email directly or view it on GitHub.

CeylonMigrationBot commented 11 years ago

[@quintesse] I mean the approach of using backticks for meta model references of your suggestion with the optional grouping of my suggestion. But I don't care about the character used for grouping, I'm just suggesting it could be optional. In my idea the @ remains the character for access to the meta model.

CeylonMigrationBot commented 11 years ago

[@gavinking] I think you're missing the point.

Would you let people write both:

Map@Entry
Map.Entry@key

And

@<Map.Entry>
@<Map.Entry.key>

That be very confusing, right?

CeylonMigrationBot commented 11 years ago

[@gavinking] Anyway, it seems to me that best combination of readability and power comes from using backticks. Then we wind up with different syntax for metamodel references and function references:

Person

is an expression of type Person(String).

`Person`

is an expression of type Class<Person,[String]>.

Person.name

is an expression of type String(Person).

`Person.name`

is an expression of type Member<Person,Value<String>>.

Person.say

is an expression of type Void(String)(Person).

`Person.say`

is an expression of type Member<Person,Function<Void,[String]>>.

The grammar for a metamodel reference would be:

"`" Type | (QualifiedType|GroupedType) "." MemberName TypeArguments? "`"

Which works out very nicely because it let's us write things as interesting as:

`<Integer|Float>.negativeValue`

Best of all, we don't need any kind of "reference" types or "metatype constructors".

CeylonMigrationBot commented 11 years ago

[@gavinking] Oh I almost forgot there is also the question of how to get a reference to a value. For toplevels/locals, the following works:

`process`

which is of type Value<Process>.

But what about for attributes? I suppose the following is workable:

`process.arguments`

which would be of type Value<String[]>. But I preferred process@arguments which is what would be natural with the infix @ syntax.

The issue is that the infix @ lets me write shit like (1+1)@negativeValue whereas that sort of thing would probably not work with the backtick-quoted syntax.

CeylonMigrationBot commented 11 years ago

[@gavinking] I suppose this is an option:

process.`arguments`

But, well, now it's getting a bit messy...

CeylonMigrationBot commented 11 years ago

[@quintesse] I still think @< > is an option, as long as you only use it for grouping of types, so you can use it for @<Integer|Float> and @<String|Map.Entry> but you can simply use process@arguments (although if you want you could write process@<arguments> which would mean the same but is unnecessary). It's not that confusing, is it?

CeylonMigrationBot commented 11 years ago

[@FroMage]

Person.name is an expression of type String(Person).

Mmmm, how do that work out for variables then?

CeylonMigrationBot commented 11 years ago

[@gavinking] WDYM?

Sent from my iPhone

On 15/05/2013, at 3:32 PM, Stéphane Épardaud notifications@github.com wrote:

Person.name is an expression of type String(Person).

Mmmm, how do that work out for variables then?

— Reply to this email directly or view it on GitHub.

CeylonMigrationBot commented 11 years ago

[@FroMage] Well, references would only be read-only. We used to have the notion of Gettable/Settable at some point.

CeylonMigrationBot commented 11 years ago

[@gavinking] Well sure, we still have Value and MutableValue.

Sent from my iPhone

On 15/05/2013, at 3:39 PM, Stéphane Épardaud notifications@github.com wrote:

Well, references would only be read-only. We used to have the notion of Gettable/Settable at some point.

— Reply to this email directly or view it on GitHub.

CeylonMigrationBot commented 11 years ago

[@FroMage] Oh, I suppose I meant person.name rather than Person.name.

BTW, whatever the syntax, will we be able to do List<Person>@method<Foo>?

CeylonMigrationBot commented 11 years ago

[@gavinking]

Oh, I suppose I meant person.name rather than Person.name.

According to this comment you could write:

MutableValue<String> name = `person.name`;

BTW, whatever the syntax, will we be able to do List<Person>@method<Foo>?

According to the grammar above, you would be able to write:

Member<List<Person>,Function<Foo,[Foo]>> method = `List<Person>.method<Foo>`;
CeylonMigrationBot commented 11 years ago

[@FroMage] Cool.

CeylonMigrationBot commented 11 years ago

[@FroMage] Is a keyword model(List<Person>) out of the question?

Will we get package and module literals too?

CeylonMigrationBot commented 11 years ago

[@gavinking] Well, there's 2 issues with that:

  1. The keyword doesn't really help a whole lot because kw operators need to have a low precedence, and so it would almost always be a keyword + punctuation, as you've shown. What I mean is, the keyword can't do anything @ can't do, and it's natural precedence is less convenient. I guess you can argue that model(some.stuff) (or more likely (model some.stuff)) is easier on the eyes than @(some.stuff), but I don't find it an improvement over backticks.
  2. This works out to be rather nasty-looking in annotation lists see (model(Foo), model(Bar)) doesn't read nicely at all.
CeylonMigrationBot commented 11 years ago

[@gavinking]

Will we get package and module literals too?

If we can decide what the syntax would be. Unfortunately we can't just use this:

`ceylon.language`

We're going to need something weird like, perhaps:

`module ceylon.language`
CeylonMigrationBot commented 11 years ago

[@FroMage]

Unfortunately we can't just use ceylon.language

Why not?

Perhaps ceylon.language is a metamodel ref to the package ceylon.language and ceylon.language/0.5 to the module?

Ideally I'd also have a metamodel ref to the current module and current package, but we don't have anything like that for the current type. Though in the case of the current type, we have a way to access it via model(this). Well, perhaps module.this and package.this would work? I suppose it goes against the outer keyword, but that one already has an issue with not being able to obtain the outer's outer so perhaps that keyword is flawed too.

CeylonMigrationBot commented 11 years ago

[@FroMage] I've just pushed support for type literals (not type members yet). Aw fuck this issue is closed and not even about type literals. Where's the issue about type literals then?