[rust-dev] 2 possible simplifications: reverse application, records as arguments

Benjamin Striegel ben.striegel at gmail.com
Mon Apr 23 08:15:26 PDT 2012


> Note: OCaml has made the choice that (K _) is a pattern that matches
> the constructor K no matter what its arity is (including none or
> several parameters). While that doesn't help with the 'tps' example
> above, it would still simplify a lot of places and does not require
> named constructor arguments. But I think that's an inferior solution.

I'm not familiar with OCaml, but I think that something along these lines
was added just last week:

https://github.com/mozilla/rust/commit/37b054973083ed4201a2ba73be6bdd39daf13cf6

An example:

enum pattern { tabby, tortoiseshell, calico }
enum breed { beagle, rottweiler, pug }
type name = str;
enum ear_kind { lop, upright }
enum animal { cat(pattern), dog(breed), rabbit(name, ear_kind), tiger }

fn noise(a: animal) -> option<str> {
    alt a {
      cat(*)    { some("meow") }
      dog(*)    { some("woof") }
      rabbit(*) { none }
      tiger(*)  { some("roar") }
    }
}

fn main() {
    assert noise(cat(tabby)) == some("meow");
    assert noise(dog(pug)) == some("woof");
    assert noise(rabbit("Hilbert", upright)) == none;
    assert noise(tiger) == some("roar");
}


On Sat, Apr 21, 2012 at 1:28 PM, gasche <gasche.dylc at gmail.com> wrote:

> I've been wondering about a problem tightly related to named
> parameters: named enum constructor arguments. SML has had the ability
> to define algebraic datatypes as sum of (named) records, and I think
> that is something that is missing in current rust. The code
> antipattern that cries for it is pattern matching for a enumeration
> name with a tedious number of "_" following it:
>
>  rust/src % grep "_, _" -R . | wc -l
>  547
>
> See also the following code example:
>
>  alt it.node {
>    ast::item_impl(tps, _, _, _) {
>      if ns == ns_type { ret lookup_in_ty_params(e, name, tps); }
>    }
>    ast::item_enum(_, tps, _) | ast::item_ty(_, tps, _) {
>      if ns == ns_type { ret lookup_in_ty_params(e, name, tps); }
>    }
>  ... }
>
> The position of the 'tps' variable among a variable number of ignored
> parameters is fragile, increase maintainance costs (if you add
> a parameter to some constructor in an enumeration, a lot of code
> changes are required just to say that you ignore it most of the time),
> and creates redundancy.
>
> This could be solved by having enum constructors with named arguments,
> and conversely a syntax for enum patterns matching named
> argument. Being able to write something like:
>
>  alt it.node {
>    | ast::item_impl(tps:tps)
>    | ast::item_enum(tps:tps)
>    | ast::item_ty(tps:tps) {
>      if ns == ns_type { ret lookup_in_ty_params(e, name, tps); }
>    }
>
> would be a win (then you can say that "tps:" is a shorthand for
> "tps:tps" or what not).
>
> Note: OCaml has made the choice that (K _) is a pattern that matches
> the constructor K no matter what its arity is (including none or
> several parameters). While that doesn't help with the 'tps' example
> above, it would still simplify a lot of places and does not require
> named constructor arguments. But I think that's an inferior solution.
>
> >  - Our records are order-sensitive, to be C-structure compatible.
> >    Keyword arguments are usually argued-for (as you are doing here) as
> >    a way to make function arguments order-insensitive. We'd need to
> >    decide whether we wanted order to matter or not.
> >
> >  - Argument-passing tends to work best when you can pass stuff in
> >    registers, not require the arguments to be spilled to memory and
> >    addressable as a contiguous slab. So we'd want to be careful not to
> >    require the "arguments structure" to be _actually_ addressable as a
> >    structure at any point. Rather, calling f(x) would be some kind of
> >    semantic sugar for `f(x.a, x.b, x.c)`, making separate copies for
> >    the sake of passing.
>
> The clean solution is to make a distinction between the data structure
> you call "records" here and the structure that is denoted by the
> parameter-building syntax. Haskell has a semantic distinction between
> "boxed tuples" (the usual thing) and "unboxed tuples" (primitive, less
> exposed, can't be used to instantiate polymorphic types). Similarly
> you would have "data records" (contiguous, C-compatible, etc.) and,
> say, "native records", that would be a different type with less
> flexibility for the user and more flexibility for the implementer: not
> adressable, possibly non-contiguous memory layout, a field order
> decided by the compiler, etc.
>
> You could then explain {x:1, y:2} as syntaxic sugard for, say,
> record(x:1, y:2), where `record` is a polytypic primitive that builds
> a "data record" from some "native record".
>
> (You could do the same for tuples and handle mixed named/unnamed
> parameters by adopting the convention existing in some languages, for
> example Oz, that a tuple (x,y,z) is just a record of numeric fields
> (0:x, 1:y, 2:z))
>
> >  - We'd have to decide the rules surrounding keyword mismatches, partial
> >    provision of keywords, argument permutation, and function types.
>
> Re. function types: if you consider those parameter-passing structures
> as "first class" (which does necessarily mean that they are convenient
> to use, for example if they're not adressable they will be
> less flexible), the natural choice is to have a family of types for
> them. Those types could come with restrictions and an unspoken kinding
> discipline, so that for example they cannot be used to instantiate
> type variables, maybe cannot be nested, etc.
>
> That's the main reason why I think one should think of such structures
> as real structures rather than syntactic sugar; it forces you to have
> a proper design for types and other aspects.
>
>
> > > another thing is that instead of passing arguments, you pass just one
> > > (anonymous) record. the record is the arguments.
> >
> > We actually had quite an argument with one of the Felix authors about
> > this. This was not, back then, a terribly realistic option during that
> > conversation (argument modes were still the primary way we were doing
> > safe references, which are not first class types). But it's conceivably
> > something we could look into if we get the argument-passing logic down
> > to "always by-value and use region pointers for safe references" (which
> > is where we're going). There remain some hitches:
> >
> >  - Our syntax isn't quite compatible with the idea; records have to be
> >    brace-parenthesized and tuples given round parentheses. They'd need
> >    reform, and the syntax is already pretty crowded.
> >
> >  - We'd have to decide the rules surrounding keyword mismatches, partial
> >    provision of keywords, argument permutation, and function types.
> >
> >  - Our records are order-sensitive, to be C-structure compatible.
> >    Keyword arguments are usually argued-for (as you are doing here) as
> >    a way to make function arguments order-insensitive. We'd need to
> >    decide whether we wanted order to matter or not.
> >
> >  - Argument-passing tends to work best when you can pass stuff in
> >    registers, not require the arguments to be spilled to memory and
> >    addressable as a contiguous slab. So we'd want to be careful not to
> >    require the "arguments structure" to be _actually_ addressable as a
> >    structure at any point. Rather, calling f(x) would be some kind of
> >    semantic sugar for `f(x.a, x.b, x.c)`, making separate copies for
> >    the sake of passing.
> >
> > So .. I can see a possibility here, but it'd be a complicated set of
> > issues to work through. Would need some serious design work. I've never
> > been intrinsically opposed to it, just felt that we were constrained by
> > other choices in the language. At the time, argument modes were
> > completely prohibitive; now it might be possible, but is still not
> > entirely straightforward.
> >
> > -Graydon
> _______________________________________________
> Rust-dev mailing list
> Rust-dev at mozilla.org
> https://mail.mozilla.org/listinfo/rust-dev
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.mozilla.org/pipermail/rust-dev/attachments/20120423/d9b3b631/attachment-0001.html>


More information about the Rust-dev mailing list