Unqualified name resolution #1439
Replies: 4 comments
-
Personally, I have been thinking of implicit inclusion of As a useful feature, this interpretation allows extending the built-in utility functions to custom user-defined types in a fairly natural way (like the The way I see it, the whole reason for deliberately giving your function a name matching a |
Beta Was this translation helpful? Give feedback.
-
Victor, thanks for neatly and clearly summarizing the proposal in the first message. First, I want to ask to refrain from using other languages in this discussion as justifications for one or another approach. I do that myself sometimes and now I see how it distracts us from thinking in the "EdgeQL box". C++/Python/PostgreSQL all have their own type systems, philosophies, restrictions, and goals. We can draw inspiration from other languages, but we shouldn't aim to copy their functionality. When we are discussing a new feature we should try to see how exactly it would benefit EdgeDB users within our type system constraints and EdgeQL capabilities. Let's try to dissect this feature proposal that way. Currently we resolve functions using "interpretation 1" as you defined it. Let's do an exercise and see what happens if we adopt the "interpretation 2". On the surface it looks like it would enable better polymorphism: essentially users would be able to overload generic Given the schema you defined previously:
the Let's now evolve the schema a bit by adding another module and subtyping the
Now the Using the "interpretation 2" that you're suggesting, the Is that what the user actually wanted to do? If I were that user, it would certainly be not. I'd expect the This is the deal breaker I see with the "interpretation 2". It would basically "force" users to have just one module (maybe most users would have one module anyways, but that's not the point). Essentially having only the "default" module is the only way how you'd enable overloading of For what it's worth I don't think this problem is solvable by allowing you to specify multiple "current modules", e.g. with There are other ways of solving the problem, like having no module for functions at all (making the global objects). But I'm afraid that ship has sailed. I really want us to stop changing the semantics of EdgeQL and focus on shipping a stable version of the product. That said, in the future it's likely we will want to solve this problem. Once we have a GIS extension users would likely want
That's questionable. Maybe you did it by accident? Or say you've deliberately defined your own To sum up, given the above complication of "interpretation 2" I'm -1 on the proposal. There's nothing wrong with the current approach. It works, it's well defined, it's consistent, and it does not create false illusions of things we don't properly support. |
Beta Was this translation helpful? Give feedback.
-
@elprans We need to decide on this in the next 2 weeks so that we have enough time before a4. |
Beta Was this translation helpful? Give feedback.
-
We've decided to keep the status quo: we don't implement cross-module function matching by short name. We do, however, need to eventually implement a concept similar to Rust's traits: a way to define a I'm going to close this issue and open two new ones for adding traits and prohiniting name clashing. |
Beta Was this translation helpful? Give feedback.
-
The status quo is that any short name is ultimately resolved to some fully-qualified name in the following manner:
(taken from our docs as of 1.0 Alpha 2)
Why is this an issue at all?
Consider how the following two queries should be resolved:
SELECT to_str(Position);
SELECT to_str(datetime_current(), 'Mon DDth, YYYY');
This is fairly unambiguous w.r.t. types and other entities with globally unique names as for any given unqualified name there's only one possible match in each of the modules, so basically we check the current module and then fallback to
std
.Things get a bit less straightforward with functions which are identified by their name + signature. So when looking for a function by name only we necessarily must allow multiple matches as a possible outcome. There are at least two way of interpreting the rule above:
std
and check there. Given that set of polymorphic function versions pick the one matching the call signature.std
(as long as thestd
function is not masked by an identical signature function from the current module). Then from this set of polymorphic functions pick the one matching the call signature.Basically the approach 1) treats all versions of the function of the same name but different signature as a single entity, a single polymorphic function (which is consistent with the polymorphic function abstraction). This reduces functions to the same status as other objects regarding having at most one with a given name in any module and the resolving logic is consequently identical.
Approach 2) treats every function with different signature as it's own separate object (which is consistent with the schema where polymorphic variants are defined through separate definitions and exist as separate objects). Unique names are not necessary, but instead it's the name + signature which have to be unique. So under this definition it makes sense that as long as functions in
std
have different signatures from the ones found in the current module, they should not be masked and must be resolved as valid polymorphic options for the given name.Another perspective to consider is what "
std
is always available" really means if we were to try to rephrase it:std
page and check there. Kinda like looking through a paper booklet.std
onto it. Then copy and possibly overwrite (for masking objects) everything from the current module onto it. This is your working namespace for unqualified names. Kinda like a couple of transparencies superimposed over each other.Beta Was this translation helpful? Give feedback.
All reactions