Open gavinking opened 8 years ago
So we would need to have a special rule
This is actually a recurring theme. For example, the definition of the syntax object foo {}
is this:
final class \Ifoo {
shared new foo {}
}
\Ifoo foo => \Ifoo.foo; //yew!
Similarly, I would love to rewrite Boolean
like this:
shared final class Boolean
of true | false {
shared actual String string;
shared new true { string="true"; }
shared new false { string="false"; }
}
And Null
/null
like this:
shared final class Null
of null
extends Anything() {
shared new null {}
}
In both cases, and in the case of the annotation constructor proposal above, I run into the problem that a constructor isn't a toplevel. Hrm, what if there were a syntax like this:
shared final class Boolean of true | false {
shared actual String string;
shared new package.true { string="true"; }
shared new package.false { string="false"; }
}
That would kill three birds with one stone.
Then this:
object foo {}
would just mean this:
final class \Ifoo {
shared new package.foo {}
}
Which is just what I want, frankly.
More generic perhaps would be outer
?
final class \Ifoo {
shared new outer.foo {}
}
Because object foo {}
need not be a toplevel, right?
@quintesse hrm I suppose you're right. Except outer
can never refer to a package. Don't tell me we need to allow both...
Well perhaps not, I guess you could just say: "it would be like writing blah blah package blah blah" for a toplevel object and "blah blah outer blah blah" for member and local objects.
It's not like you'd ever want to use that syntax over the normal object
syntax anyway... right?
So I implemented support for the new package.constructor
syntax in the typechecker—really trivial, thought it surely could have bugs—and, believe it or not, it's already working for callable constructors on the JVM. (But not for value constructors, and not on the JS backend.)
Still to do:
shared
for these things, and implement that,I find the syntax pretty natural and convenient. And it really does the work of nailing down what object
means which is very nice.
And it really does the work of nailing down what
object
means which is very nice.
Well, OK, wait, let me walk that back a little. We can have nested object
s and local object
s. The package
qualifier nails down the semantics of toplevel object
s, which are the most important, since they can be switch
ed. Adding an outer
qualifier would achieve the same for nested objects.
But local objects remain an outlier: we currently have no keyword that identifies the immediately-containing scope. (outer
always refers to the containing class/interface.) Now, a keyword like that would be nice anyway, but it doesn't exist right now.
Now, a keyword like that would be nice anyway
A couple of options: body
, block
.... or even just function
.
Using function
within the body of a constructor or getter/setter would be pretty weird, but since I think it's essentially never going to be used explicitly in those contexts in practice, it might be OK.
Ah: body
sucks because it would hammer Html { head = ... ; body = ... ; }
.
And block
is probably out for much the same reason.
We could use out
, perhaps...
Or, the other obvious option is to just use an annotation: promoted
, possibly.
Actually there is a use for this that has nothing to do with constructors, I suppose. According to §4.2.2, we can also import members of toplevel object
s.
It might be nice if you could write:
import ceylon.language { milliseconds }
As an alternative to:
import ceylon.language { system { milliseconds } }
Just by annotating system.milliseconds
with whatever we choose: package.
or promoted
or whatever.
Would this also be allowed?
shared class C() {
shared object o {
shared promoted String s => "s";
}
}
shared void run() => print(C().s);
@lucaswerkmeister well currently we don't support this:
import pack { C { o { s } } }
So, no.
Not that I'm agreeing with this whole constructor thingie, but since they're not going away (:sob:), I think constructors should simply naturally be accessible from the same scope as its class... Also, @gavinking, I'm confused by your Boolean
and Null
example thingies... Shouldn't classes with constructors not have parameter lists?
Shouldn't classes with constructors not have parameter lists?
Yes of course. Copy/paste error.
An good alternative to promoted
, that is of more general use, would be to introduce a streamlined syntax for class
and function
aliases for the case where you're not changing the type or parameter list. For example:
function joinWithCommas => ", ".join;
And:
class Strings => Array<String>;
Which we currently force you to write using a much more verbose syntax, for example:
function joinWithCommas({Object*} objects) => ", ".join(objects);
Then, we could rewrite my annotation example above like this:
shared final annotation class Doc {
shared String text;
shared new doc(String text) {
this.text = text;
}
}
shared function doc => Doc.doc;
Or, more simply, as:
shared final annotation class Doc(text) {
shared String text;
}
shared function doc => Doc;
But Boolean
would not be improved as much:
shared final class Boolean
of true | false {
shared actual String string;
shared new true { string="true"; }
shared new false { string="false"; }
}
shared value true = Boolean.true;
shared value false = Boolean.false;
@gavinking
Well, currently you can do that:
value joinWithCommas => ", ".join;
and:
function joinWithCommas({Object*} objs);
joinWithCommas = ", ".join;
The first is cleaner, but the last allows you to override methods.
I really like the idea of the simplified class aliases, but honestly I feel like the function aliases looks a lot like value declarations with a small semantic difference that may makes sense implementation-wise on the jvm, but conceptually, it just feels like a clunky, and unnecessary difference...
But it's not quite the same: you lose the parameter names, which are very important in this case.
Now that we have the notion of a constructor, and they happen to have lowercase names, it would make more sense if annotation constructors were constructors.
The only thing that doesn't quite fit here is that it looks like you would have to import the
doc
annotation like this:That would be quite inconvenient, and not backward compatible. So we would need to have a special rule that says you can import an annotation constructor like this:
I don't think that's too offensive a notion.