27 also talks about this but I think this issue is more specific. Take this as example:
use "mylibrary/users"
# defined in "mylibrary/users"
let user = get({
"name": "Foo Bar",
})
# also defined in "mylibrary/users"
let foo = User{name: "Luna"}
foo.bar()
Even though this syntax sugar is great for methods defined for a given type, I think it becomes really weird when it comes to functions that are not "meant" to be methods. And the (lack of) qualification of the exported symbols confuses me about the types defined in those modules (what if two different modules had a type with the same name?). This adds an extra layer of complexity for the user to deal with and drastically reduces the readability of the code for other users.
If we add the possibility to optionally "qualify" the module exports like this:
use "foo" as foo
Then it becomes really unclear how the methods for the types defined in that module would be called.
use "mylibrary/users" as users
let foo = users.User{name: "Anonymous"}
foo.method()
# the call above would parse as "method(foo)" but "method" is unresolved because it's inside the
# "users" module
Also, if we could specify what would be exported (like in ES6), but all the rest would be auto-exported as well (see #27), then what's the point?
use "mylibrary/users" (get, User)
This would work if we only export what's specified, but if one uses too much symbols from that module it adds a lot of polution to the code (imagine a file with 10 or more imports and each one with a lot of symbols).
Possible solution
First, we would need to get rid of the foo.bar() syntax sugar (multiple-dispatch still remains). Instead of parsing it as bar(foo) it would remain as it is, and then we lookup method bar on the type of foo. And how methods would be defined? I've come up with a couple of syntaxes.
type Foo
name: string
x, y: float
def bar(name: string)
self.name = name
end
end
# or
def Foo.bar(f:, name: string)
# 'f' would be automatically of type "Foo"
f.name = name
end
# or even
def Foo.bar(f | name: string)
# 'f' would be automatically of type "Foo"
f.name = name
end
The first one doesn't really looks like something you would find in a Luna file, so I think the second or the last one is a better fit.
As for modules, the last part of the module name would be what Luna would use to qualify it's exported symbols, for example:
use "mylibrary/users"
let user = users.get({
"name": "Foo",
})
let foo = users.User{name: "foo"}
foo.bar()
I think this fits better with luna's goals (with emphasis on the 'explicit' part) and as a consequence, improves readability of the code. Even if this doesn't get implemented the discussion might lead to something which can benefit from both models.
PS: this would bring pipes back to replace the current syntax sugar (#35)
27 also talks about this but I think this issue is more specific. Take this as example:
Even though this syntax sugar is great for methods defined for a given type, I think it becomes really weird when it comes to functions that are not "meant" to be methods. And the (lack of) qualification of the exported symbols confuses me about the types defined in those modules (what if two different modules had a type with the same name?). This adds an extra layer of complexity for the user to deal with and drastically reduces the readability of the code for other users.
If we add the possibility to optionally "qualify" the module exports like this:
Then it becomes really unclear how the methods for the types defined in that module would be called.
Also, if we could specify what would be exported (like in ES6), but all the rest would be auto-exported as well (see #27), then what's the point?
This would work if we only export what's specified, but if one uses too much symbols from that module it adds a lot of polution to the code (imagine a file with 10 or more imports and each one with a lot of symbols).
Possible solution
First, we would need to get rid of the
foo.bar()
syntax sugar (multiple-dispatch still remains). Instead of parsing it asbar(foo)
it would remain as it is, and then we lookup methodbar
on the type offoo
. And how methods would be defined? I've come up with a couple of syntaxes.The first one doesn't really looks like something you would find in a Luna file, so I think the second or the last one is a better fit.
As for modules, the last part of the module name would be what Luna would use to qualify it's exported symbols, for example:
I think this fits better with luna's goals (with emphasis on the 'explicit' part) and as a consequence, improves readability of the code. Even if this doesn't get implemented the discussion might lead to something which can benefit from both models.
PS: this would bring pipes back to replace the current syntax sugar (#35)