component-model icon indicating copy to clipboard operation
component-model copied to clipboard

Consider allowing "associated functions" and "associated methods" on non-resource types

Open Dimchikkk opened this issue 1 year ago • 3 comments

For additional details and related information, please refer to https://github.com/bytecodealliance/wit-bindgen/issues/815

Dimchikkk avatar Jan 21 '24 14:01 Dimchikkk

Thanks for filing; this seems like an interesting idea!

So as a starting point, I think it would make sense to relax the validation rules for [static]-annotated functions to allow not just resource types, but any named (via import/export) type. (For the other annotations, it's not clear to me if they make sense for non-abstract-types, so maybe we just start with static.) That seems easy enough.

Then the next question is how much support we want to give this in WIT (do you have to write %[static]foo.bar: func(...) or do we have some nicer syntactic sugar. For type definitions with curly brace bodies, you could imagine allowing nested static definitions (the same way as with resource types), e.g.:

record coord {
  x: u32,
  y: u32,
  add: static func(lhs: coord, rhs: coord) -> coord;
}

but that won't work for all type definitions (say, type foo = ...; definitions), and maybe that's non-trivial extra syntactic work and perhaps an unwanted new source of grammatical ambiguities (e.g., record needs to always be able to distinguish associated functions from fields).

Alternatively, we could have some new statement that that could work uniformly for any type and would just be a trivial name desugaring, e.g.:

record cord { ... }
extend coord with {
  static add: func(lhs: coord, rhs: coord) -> coord;
}

this syntax could also be useful to adding [method] functions to a resource type defined in a separate interface:

interface fancy-http {
  use wasi:http/types.{request};
  record fancy-metadata { ... };
  extend request with {
    extra-metadata: func() -> extra-metadata;
  }
}

which is a use case that has come up separately in the context of wasi-http being extended with additional methods in vendor-specific interfaces.

I'm not sure which is the right way to go (or I suppose we could do both, addressing different scenarios); I'm just throwing out options at the moment.

lukewagner avatar Jan 22 '24 18:01 lukewagner

If each interface is allowed to generate extension methods for the import type, then when an interface containing a method with the same name is introduced at the same time, is there a way for each language to distinguish which function should be called?


In rust this can be selected via <T as ExtendInterfaceName>.

In C# this can be selected via import static ExtendInterfaceName = XXX.

I'm not sure how to choose other languages, such as structural languages like js.

oovm avatar Mar 30 '24 07:03 oovm

Ah, are you asking about what happens in the case of a name clash (e.g., if two interfaces i and j add a foo method to the same resource type r)? I think in this case, the bindings generator would fall back to a desugared (non-member) declaration (e.g., fully qualifying the method name with the containing interface name). Or perhaps these desugared names are always present as the base declarations and then the sugar names are only introduced when there is no ambiguity. IIRC, jco uses a similar sort of strategy for exports to avoid requiring full interface-name qualification when there is no ambiguity.

lukewagner avatar Apr 01 '24 15:04 lukewagner