(no title)
lerno | 1 month ago
In particular, C3's "path shortening", where you're allowed to write `file::open("foo.txt")` rather than having to use the full `std::io::file::open("foo.txt")` is only made possible because the namespace is distinct at the grammar level.
If we play with changing the syntax because it isn't as elegant as `file.open("foo.txt")`, we'd have to pay by actually writing `std.io.file.open("foo.txt")` or change to a flat module system. That is a fairly steep semantic cost to pay for a nicer namespace separator.
I might have overlooked some options, if so - let me know.
zephen|1 month ago
> In particular, C3's "path shortening" ... we'd have to pay by actually writing `std.io.file.open("foo.txt")` or change to a flat module system.
You can easily and explicitly shorten paths in other languages. For example, in Python "from mypackage.mysubpackage import mymodule; mymodule.myfunc()"
Python even gracefully handles name collisions by allowing you to change the name of the local alias, e.g. "from my_other_package.mysubpackage import mymodule as other_module"
I find the "from .. import" to be really handy to understand touchpoints for other modules, and it is not very verbose, because you can have a comma-separated list of things that you are aliasing into the current namespace.
(You can also use "from some_module import *" to bring everything in, which is highly useful for exploratory programming but is an anti-pattern for production software.)
lerno|1 month ago
I don't want to get too far into details, but it's understandable that people misunderstand it if they haven't used it, as it's a novel approach not used by any other language.
alcover|1 month ago
I don't see the issue. Just look up the id ? Moreover, if modules are seen as objects, the meaning is quite the same.
> checking is much easier if the namespace is clear from the grammar.
Again (this time by the checker) just look up the symbol table ?
lerno|1 month ago
If instead we had foo.bar(), we cannot know if this is the method "bar" on local or global foo, or a function "bar()" in a path matching the substring "foo". Consequently we cannot properly issue 4, since we don't know what the intent was.
So far, not so bad. Let's say it's instead foo::baz::bar(). In the :: case, we don't have any change in complexity, we simply match ::foo::baz instead.
However, for foo.baz.bar(), we get more cases, and let us also bring in the possibility of a function pointer being invoked: 1. It is invoking the method bar() on the global baz is a module that ends with "foo" 2. It is calling a function pointer stored in member bar on the global variable baz is a module that ends with "foo" 3. It is calling the function bar() in a module that ends with "foo.baz" 4. It is calling the function pointer stored in the global bar in a module that ends with "foo.baz" 5. It is invoking the method bar on the member baz of the local foo 6. It is calling a function pointer stored in the member bar in the member baz of the local foo
This might seem doable, but note that for every module we have that has a struct, we need to speculatively dive into it to see if it might give a match. And then give a good error message to the user if everything fails.
Note here that if we had yet another level, `foo.bar.baz.abc()` then the number of combinations to search increases yet again.