Eigenstate: myrddin-dev mailing list

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[RFC PATCH 0/2] impl specialization and lookup changes


These two patches change how trait declarations are specialized and
looked up.

Here is the motivation:

In libwl, I have one common object struct, and for each interface, a new
type name for object. For error reporting, I need to keep track of the
interface name in the object. In all but one case, I know the type of
object I am creating, so can just create the object with the appropriate
interface name. However, global objects are created with the
wl_registry.bind request, which can return any interface type. The
object interface name is sent in the request to the server.

Currently I have this implemented as a generic function takes an interface
name and returns a @a. However, nothing checks that this interface name
matches the interface type. Ideally I'd be able to define a trait
isobject which declares an interface name.

	trait isobject @o =
		Interface: interface
	;;

However, since the type of Interface does not refer to @o, only one type
can implement it (trait declarations are specialized with a name
based on its type alone).

The first patch adds new syntax

	impl(name, type)

which behaves almost exactly like `name`, except that the trait
parameter is specified explicitly. This change alone is not very useful,
but does allow you to disambiguate a trait declaration when used in a
generic context. For example.

	trait default @a =
		Def: @a
	;;
	impl default int =
		Def = 12
	;;
	const main {
		std.put("Def: {}\n", impl(Def, int))
	}

Otherwise, you'd have to write

	const main {
		var def: int = Def
		std.put("Def: {}\n", def)
	}

in order to choose the implementation of Def you want.

The second patch makes it so trait declarations are specialized by the
trait parameter in addition to the declaration type. This way, multiple
types can implement traits which may have a declaration with a concrete
type (i.e. one that does not allow you to deduce the trait parameter).

With both of the patches together, you can do something like

	trait name @a =
		Name: byte[:]
	;;
	impl name int =
		Name = "int"
	;;
	impl name char =
		Name = "char"
	;;
	generic f = {@a::name
		std.put("name: {}\n", impl(Name, @a))
	}
	const main = {
		f('a')
		std.put("name: {}\n", impl(Name, int))
	}

ALTERNATIVES:
These changes aren't strictly necessary, and can be worked around by
having a trait like

	type tag(@a, @t) = @a
	trait t @a =
		foo: tag(int, @a)
	;;
	impl t bool =
		foo = 6
	;;
	const main = {
		var x: tag(int, bool) = foo
		var y = (x: int)
	}

This seemed awkward enough for me to warrant the changes, which I think
are fairly unobtrusive.

DISCLAIMER:
I am in way over my head with this type inference stuff so I probably
did something wrong in these patches. They probably need a careful
review.

Michael Forney (2):
  Add impl(type, name) to retrieve a particular implementation of a
    trait decl
  Specialize impl declarations on impl type in addition to decl type

 doc/lang.txt               | 12 ++++++++++--
 mbld/deps.myr              |  2 +-
 parse/export.c             |  2 ++
 parse/gram.y               |  6 +++++-
 parse/infer.c              | 34 ++++++++++++++++++++++++----------
 parse/parse.h              |  6 +++---
 parse/specialize.c         | 16 +++++++++++-----
 parse/use.c                |  5 +++++
 test/implexpr-concrete.myr | 15 +++++++++++++++
 test/implexpr.myr          | 18 ++++++++++++++++++
 test/tests                 |  3 ++-
 11 files changed, 96 insertions(+), 23 deletions(-)
 create mode 100644 test/implexpr-concrete.myr
 create mode 100644 test/implexpr.myr

-- 
2.13.2


Follow-Ups:
[RFC PATCH 1/2] Add impl(type, name) to retrieve a particular implementation of a trait declMichael Forney <mforney@xxxxxxxxxxx>
[RFC PATCH 2/2] Specialize impl declarations on impl type in addition to decl typeMichael Forney <mforney@xxxxxxxxxxx>
Re: [RFC PATCH 0/2] impl specialization and lookup changesQuentin Carbonneaux <quentin@xxxxxx>