static methods and attributes
See original GitHub issueSo, I’m throwing this one out there to see what ya’ll think.
A long time ago I decided that Ceylon would not have static methods. The reason for this was that I always hated them in Java: in order to declare a regular function, you were forced to define a rubbish class with no instances, just to stick the function on it, and then to call that function, you had to do something nastily verbose like Integer.parseInt()
. These functions had nothing to do with the schema of any type, and they don’t have access to the instance-level state of the class, they are just stuck onto the side of a class for no good reason.
Some things happened since that time to make me want to reevaluate this:
- We had to anyway build almost everything needed to support static methods into the typechecker in order to support Java interop.
- We added constructors, which sorta look like static methods. In particular, they are invoked on a class name, instead of an instance.
- People started asking for “factory functions”, which are, essentially, a particular sort of static method.
- I figured out how to resolve the “don’t have access to the instance-level state” conundrum: simply require that static members be declared at the beginning of a class with constructors, before any instance-level state is allocated.
- I started writing lots of code that interoperates Java with Ceylon and found it sorta weird that I was totally comfortable calling Java static methods in Ceylon, but couldn’t actually write a static method in Ceylon.
- I started wanting to define a constant values shared between all instances of a class, without polluting the package namespace.
- I ran into a (anti-)pattern used in IntelliJ APIs where a service implementation is supposed to define a certain specially-named static member. I couldn’t do this in Ceylon, so this class had to be written in Java.
- I realized that there actually is one very good motivation for
static
: static members can bypass the visibility restrictions that are imposed on toplevel functions, and access private state of instances of the class. This is unambiguously useful, especially since we don’t (yet) have package-private.
Thus, at this point, it would be sooo easy to add static methods and attributes (it basically amounts to one new annotation), that it’s hard to see why we shouldn’t. It would look like this:
class Integer {
shared static Integer|SyntaxError parse(String string) => internalParse(string);
shared static Integer sum({Integer*} integers) => integers.fold(0)((s,x)=>s+x);
shared new (Integer i) { ... }
...
}
Note that I don’t see why interface
s couldn’t have static members. So this need not just be for class
es.
So, pros and cons of doing this include:
Pros:
- it makes it slightly easier to port Java code to Ceylon (paste-Java-as-Ceylon will work a little better)
- it results in the more-expressive
Integer.parse(text)
andInteger.sum(totals)
instead ofparseInteger(text)
andintegerSum(totals)
- it’s easier to “discover”
Integer.parse()
andInteger.sum()
in the IDE than it is to discoverparseInteger()
today - it provides a nice way to share private state/operations between a class and functions which operate on its instances,
- it provides a way to define class-local constants,
- it probably resolves the perceived need for “factory functions”
- it makes constructors look less “irregular”, since
static
members and constructors share a essentially the same rules - it slightly eases the cognitive tax of programming in mixed Java/Ceylon projects, since that’s one more construct that maps across cleanly (ditto for JavaScript where you have stuff like
Math.xxxx
) - it might make some things from Dart and Typescript easier to represent @jvasileff @lucaswerkmeister wdyt?
Cons:
- it might encourage Java-isms of creating rubbish classes just to stick functions on them (but it’s easy enough to tell people to use
object
instead ofclass
for that - the people (person?) who think(s) that introducing constructors were a terrible mistake that makes the language less regular might perceive this as doubling down on that irregularity rather than resolving it by make it less irregular
- it’s an additional language feature that is clearly not a critical thing we have to have
- it might be more difficult to implement in Dart and JS than it is in Java (I doubt this)
- I would have to admit I was wrong about something
Thoughts?
Issue Analytics
- State:
- Created 7 years ago
- Reactions:1
- Comments:143 (143 by maintainers)
Top GitHub Comments
We should probably think about how this plays together with #4005 (most recent proposal in https://github.com/ceylon/ceylon/issues/4005#issuecomment-156656948), to make sure we’re not putting any obstacles in our own way for when we decide to address that issue. What’s the relation between static type members and polymorphic type members?
It is now rejected by the typechecker.