Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Interface Method namespaces #1266

Open
drewc opened this issue Aug 23, 2024 · 3 comments
Open

Interface Method namespaces #1266

drewc opened this issue Aug 23, 2024 · 3 comments
Assignees

Comments

@drewc
Copy link
Collaborator

drewc commented Aug 23, 2024

The issue is simple: dynamic methods have no namespace and interfaces cast to them. Also, different interfaces (aka typeclasses) could have different methods with the same name. And curly's should {be-not-prefixed 'by-default 'for 'KISS}

In short; module/name#interface-name::method-name for the default allows both easy dispatch AND static signature checking while keeping name and module separation to make unintended duplication difficult.

The solution is a namespace: keyword that acts similar to the externone only defaults to the interface name. If it's #f, no namespace. It could also be prefix:.

So, (interface foo (bar baz)) will, at prototype, look for and bind the foo::bar method. It could then, if foo::bar does not exist, look for the :bar method, and then the bar method. That solves almost all the problems, right?

Then (interface (bat foo) (xyz n)) could first look for the bat::bar method before the foo::bar et al methods. That allows for some interesting specialization while allowing a hierarchy. outside of class/types.

But (interface (fu namespace: foo) (bar me)) could lookup foo::bar as well?

Should the prefix actually be module/name#foo::bar by default?
I think that may be better as I can have interfaces with the same name and same functions but in a different space.

So (rename: food foo) on an export and then in another module (interface (foo food) (bar baz)) could have an another/module#foo::bar first dispatch attempt?

Thoughts?

@vyzo vyzo changed the title Interface Method namespace: or prefix: keyword for static/dynamic casts and dispatches Interface Method namespaces Aug 23, 2024
@vyzo
Copy link
Collaborator

vyzo commented Aug 23, 2024

I think this is very important for multiple reasons:

  • avoid conflict in method names
  • allow objects to implement multiple interfaces with conflicting method signatures, and safely do so
  • (eventually) allow static type checking/inference on method implementation signatures (and you get implicit :- for higher performance)

The proper solution is for each interface, we define a method namespace (default: the module namespace + the interface name + the method name, so as drew suggested module#Interface::method.
The interface macro will emit a linearized list of method names in the interface descriptor, instead of a single unnamespaced one, and similary the prototype creation will resolve for a particular class in the linearized order.
Finally, the defmethod macro will get a interface: directive to do the proper namespacing at the binding site.

This will leave the global namespace reserved for dynamic dispatch methods, which is a big enough namespace.
The restriction will be that you need to namespace your defmethods, but I was planning to enforce that anyway for static type checking and safety.

@vyzo
Copy link
Collaborator

vyzo commented Aug 23, 2024

cc @fare

@vyzo vyzo added this to the Gerbil v0.19: Benko milestone Aug 23, 2024
@vyzo vyzo self-assigned this Aug 23, 2024
@vyzo
Copy link
Collaborator

vyzo commented Dec 16, 2024

Implementation in #1287

Remaining TODO: validate method signature and inject type assertions in the implementation.

vyzo added a commit that referenced this issue Dec 16, 2024
This implements namespaces for interface methods, as discussed in #1266.

In brief:
- each interface has a namespace
- interface method resolution uses a linearized (c4) search for
appropriate methods, bottoming at the unqualified method name (for UX
and backwards compatibility)
- it becomes undesirable (and not easy) to call a namespace method
dynamically; you really have to go through the interfrace -- and this is
the desirable and safe way to invoke an interface method, as the
contract is enforced. It is also now safe to assert the interface method
types in the method implementation as you really have to go out of your
way to bypass the contract.

Follow up:
- what is not implemented yet is to validate the method implementation
against the interface method signature and in fact inject the signature
into the method automatically. This has many benefits (both performance
and safety), but it is also more complicated to implement. We can tackle
this in a follow up pr.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants