Skip to content

What's the naming/conceptual convention around WIT packages, worlds, and interfaces? Are there parallels in other languages? #295

@jcbhmr

Description

@jcbhmr

Here's a concrete example: If I want to turn this very simple Rust package https://docs.rs/unicode-math-class/latest/unicode_math_class/ into a WebAssembly component using https://github.com/bytecodealliance/cargo-component, what should I call the package, world, and interface?

For instance in the example Rust package, there's these levels of hierarchy:

  • package: unicode-math-class on crates.io
  • crate: unicode_math_class is the singular lib crate in the package. Rust supports N bin + 1 lib crate per package which maps well-ish to multiple worlds?
  • modules: there's no submodules like serde::de so it's just the root module.
  • items: the MathClass enum, REVISION constant, and 'class()' function.

In my brain those map relatively cleanly onto the package/world/interface model like so:

  • package: jcbhmr:unicode-math-class from my username + Rust package name. Sorta Docker-like two-part names.
  • world: unicode_math_class from lib crate name -- unicode-math-class due to no underscores
  • interface: since I need to put the enum math-class {} inside an interface... but the MathClass is in the root module... What should I do? Is there a naming convention like interface crate { ... }? Or mod, root, module, iface, exports, main, lib, it, default, or something else? Single metacharacters like $,_,- aren't allowed 😢. If it had any sub-modules I guess those would map well to serde::de => world serde {}; interface de {}.
WIT snippet of that
package jcbhmr:unicode-math-class;

world unicode-math-class {
  // Can't export enum without a wrapping interface! What do you call the interface tho?
  export x: interface {
    enum math-class { ... }
    // No consts; compromise with getter func.
    revision: func() -> u8;
    // No char type; compromise with string.
    class: func(c: string) -> math-class;
  }
}

Is there a better way? 🤔

I'm looking for the convention. Or just some general "well here's what I do" ideas. I'm having decision paralysis and I'd like to get some other opinions besides my own biased one.


To add another example to my question: what about other languages? Another ezpz to-WASM language besides Rust is JavaScript https://github.com/bytecodealliance/jco#componentize

Here's my guess as to how something like https://tsdocs.dev/docs/string-width might be paralleled to WASM component WIT:

You've roughly got these hierarchical levels:

  • npm package: string-width
  • subpath-exports: just ./ (no string-width/emojifier sub-exports)
  • the exported items: so just default fn and Options type in this case.

In my brain I think that could be modeled as:

  • package: jcbhmr:string-width since I'm publishing it + package name
  • world: different worlds for each subpath-export. Like string-width => world string-width {} but string-width/emojify => world string-width-emojify {}. Each world is an "entrypoint" set of imports/exports just like an ES module is.
  • interface: you can eliminate the need for a redundant interface exports { default: func(...) } by just putting the func() on the world. But that doesn't work for modules that export enums, records, or resources. Specifically the options bag record.
WIT snippet of that
package jcbhmr:string-width;

// 'import {...} from "string-width"'
world string-width {
  use options.{options};
  // ugh. now the function is free of an interface but the record type
  // needs one. you might as well just stick them both in the interface?
  export default: func(string: string, options: option<options>);
  export options;
}
interface options {
  record options {
    ambiguous-is-narrow: bool,
    count-ansi-escape-codes: bool,
  }
}

Is there a better way? 🤔

no, the string-width/emojify export doesn't actually exist


As you might be able to tell, I'm a bit puzzled about when/how to use interfaces and how to name them idiomatically when they get in the way of flatter hierarchies. I'm trying to understand the concepts that package/world/interface are supposed to represent and apply them to existing programming concepts that
I know. Thanks for reading my TED talk lol

p.s. has this already been discussed somewhere/somehow? it must've...

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions