Open milutinovici opened 7 years ago
Actually, I have another plan for static (used only inside types). I also don't like the idea to have to tag every instance methods with a first parameter this
or self
as you have usually a lot more instance methods than static methods, it becomes quickly a typing and visual annoyance.
For static
methods, I expect to have them as a separate group inside a type so that you can inherit a static from a trait (it means that you can effectively bring a contract to static methods), typically like this:
class MyType
{
static implements MyFactory
{
public create() -> MyType
{
...
}
}
}
That would be actually the only usage of static, but actually, I don't know yet if I will even use the term static
but use maybe a different keyword in order to avoid confusion (For example, Kotlin is using the term companion
for static class methods )....
and yes, for mutable static variable, fields, they won't be allowed. Only immutable data through the const keyword
(Note also that the syntax is far from fixed yet. so the above may change with the introduction of a func
or fun
to declare a method)
Well, let me preface this, that I am by no means a language designer, but I'll try to defend my position. Presumably interface definition, as you have imagined it, would look like:
// can only have static methods
trait MyFactory<T>
{
create() -> T;
}
// can only have instance methods
interface Stringable
{
toString() -> string
}
My suggestion would look something like this:
interface MyFactory<T>
{
create() -> T;
}
interface Stringable
{
toString(this) -> string;
}
interface StringyFactory<T> : MyFactory<T>, Stringable
{
}
In my view it has 3 advantages. It's simpler (has fewer concepts), more composable, and more explicit. Yes, you pay for explicitness with a couple of extra characters, but I think it's worth it.
Regarding a func keyword, I like the idea. But you can use fn instead. There... I saved you 2 chars. You can use the surplus for this parameter 😄
Well, let me preface this, that I am by no means a language designer, but I'll try to defend my position. Presumably interface definition, as you have imagined it, would look like:
I'm not an expert at all, so discussion is open. 😉
I'm not completely against the idea (of the this/self parameter), but I'm trying to find the sweet pot. My main complain about having to describe "self" for instance methods is that in practice, you will have a lot more instance methods in a framework/API than static methods. So it means that it puts the burden when writing instance methods, and I find this quite unfortunate.
In my early thinking right now about this (again, as It is not yet part of my main preoccupation right now, things will change, and this discussion is important when I will have to design this part), trait
don't have a usage for instance only, so it means that you could have:
trait MyFactory<T>
{
create() -> T;
}
trait Stringable
{
toString() -> string
}
trait StringyFactory<T> : static MyFactory<T>, Stringable
{
}
But we could also decide instead describe the static-ness at the method level (and it would be similar to C# when implementing them):
trait MyFactory<T>
{
static create() -> T;
}
trait Stringable
{
toString() -> string
}
trait StringyFactory<T> : MyFactory<T>, Stringable
{
}
I don't want to follow the strictness of "explicit at all cost is the way to go", but when I will revisit this, we will see, things like this are not set in stones.
Regarding a func keyword, I like the idea. But you can use fn instead. There... I saved you 2 chars. You can use the surplus for this parameter
As I explained in one blog post (the first token part), I don't like much the squashing that rust has done on some keywords. Again, that's a difficult balance to find between conciseness and expressiveness/explicitness (where here I vote for expressiveness). I prefer something that preserve some semantic when reading like function. Some language like Kotlin have chosen the word fun
, coming from ML language, but I have seen people complaining about this choice.... Swift has taken func
: I find it quite practical between the more verbose function
from Javascript and the more terse version fn
from rust.
Well, maybe it's just me, but I spend much more time reading the code, then actually writing it. Like orders of magnitude more. So I would optimize for readability, not writability. Anyway, I hope i have given you some food for thought.
Well, maybe it's just me, but I spend much more time reading the code, then actually writing it. Like orders of magnitude more. So I would optimize for readability, not writability.
I agree. But readability is something that can become quickly a matter of taste or habit... something that probably not equal for everyone... Precisely, I said above that reading for example, func
should be more readable than fn
(or int32
more than i32
), because when you pronounce them, they are already an actual prefix of an existing word (func
tion, int
eger), so while many could agree with me here, I'm pretty sure many will not...
Then to which point an abbreviation is considered readable for a new comer vs someone used to a language? When I was younger, I loved to program in assembler, sometimes directly dumping hexa values in place of asm... the more I'm getting older, the more I prefer having something a bit more verbose and less cryptic... Rust has chosen some very terse syntax with the usage of backstick ` for lifetime or the &
for reference types and when reading a Rust program, I have a really hard time reading it, mostly because I'm not familiar with it, but also because they choose a terse syntax that is not necessarily pleasant to read...
In the end, is this really only a problem of readability/writability but more about what is a familiar syntax?... Many functional programmers will find the rust syntax too much C oriented (e.g "I don't want to use brackets!")... as mostly an imperative coder, I found the F# syntax for functions very disturbing at first when you are trying to decipher where the parameters of a functions are declared (let x y z = ...
) because my mental model is bound to "a function is usually called with parenthesis..." It is even funny here, because the non functional version is also closer to "regular" mathematics (the one you learn at school), for which functional programming should theoretically be closer... but they took inspiration from Lambda calculus which is a is a formal system in mathematical logic for expressing computation based on function abstraction and application using variable binding and substitution and that make sense in its own, but is this Lambda calculus more readable?
When for example I refer to trying to find a sweet pot, this is obviously not an universal sweet pot, there is nothing like this... this is largely influenced by my own experience with programming language... and thus quite opinionated...
Anyway, I hope i have given you some food for thought.
You are welcome, discussions like this can help us to shape better ideas! 😉
Of course you are right. I am biased toward c-like syntax. I like my brackets and my parenthesis.
It is even funny here, because the non functional version is also closer also to regular mathematics (the one you learn at school), for which functional programming should theoretically be closer...
Yeah this caught my eye also 😄
Regarding the function keyword, I don't have a strong opinion, because it doesn't really change much, one way or the other.
On the other hand, this parameter is central to the definition of instance methods. It's a defining characteristic. A novice programmer would wonder (as did I, when I was younger), where did this come from? How do I have access to this magical thing. Can I use it outside of methods? It isn't clear.
On the other hand, this parameter is central to the definition of instance methods. It's a defining characteristic. A novice programmer would wonder (as did I, when I was younger), where did this come from? How do I have access to this magical thing. Can I use it outside of methods? It isn't clear.
That's an interesting point, because it brings its own set of questions. Even if you declare explicitly this
:
public MyClass {
public mymethod(this, param1: int32) -> int32)
{
}
}
you will wonder how it comes at the callsite:
myclass.mymethod(5)
Typically here, you don't see this
, it is not passed as the first parameter of the method. Don't you think that there is a bit of a similar magic here? Following your argument, I would have to write something like this instead:
MyClass.mymethod(myclass, 5)
and that would maybe make more sense... so unless you use this syntax, you still need to know from where this
is coming. I don't remember that problem of apprehending this
when first using Java... that's a fundamental concept in OO language, something that you learn quite early at school, this
is usually an hidden argument, so why choosing to hide it on one side and not on the other?
OTOH, the this
keyword in Javascript can be very confusing depending on the context it is called... not something I like. A language like PHP 5 is even mixin $this
and self
, which can turn to be very disturbing...
OTOH, the this keyword in Javascript can be very confusing depending on the context it is called... not something I like. A language like PHP 5 is even mixin $this and self, which can turn to be very disturbing...
Yeah that behavior is completely broken.
Following your argument, I would have to write something like this instead:
MyClass.mymethod(myclass, 5)
Well, not that you'd have to, but you could, if you wanted to. And this illustrates, they are essentially the same thing. They are just functions. The instance ones just have a little bit sugar on top.
you will wonder how it comes at the callsite:
myclass.mymethod(5)
Well that's where some magic can be useful in finding that sweet spot.
that's a fundamental concept in OO language, something that you learn quite early at school
Well I am talking about a period when I was learning OO concepts in school. And my first OO language was in fact Java.
Thinking about it, one strong benefit for having an explicit self/this is the ability to attach modifiers to it. And this is quite an important feature because when I was sketching mutable
, immutable
, transient
modifiers they were declared along the visibility modifiers that are attached to a method, but something like mutable
must be attached to the instance (like rust with &mut). So that could indeed justify this approach. So I will keep this in mind when working later on this part.
Yes! That's a great point. If you haven't read @joeduffy wrote several blog posts about midori, which are a real goldmine of language design insight.
If you haven't read @joeduffy wrote several blog posts about midori, which are a real goldmine of language design insight.
indeed, the idea behind Stark is largely influenced by the work on midori. My first post introduction about Stark was referring to it 😉
Oh right. I forgot that you mentioned it 😄
I think there is no need for a static keyword. For methods, distinction could be that instance methods have 1st this parameter, and static ones don't.
Because this is already an implicit parameter in instance methods. This way it would be explicit. I think rust is doing something similar.
static fields/properties.
Mutable static is bad, so it shouldn't be supported at all. This leaves static readonly which could just be const
Hope this helps