5
$\begingroup$

In my WIP language, all functions are really just variables with a callable type. That is, a function call foo(bar) is parsed into the following AST:

         CallOperation
           /       \
         expr     args
         /           \
 VariableAccess  VariableAccess
        |               |
       foo             bar

All functions defined on structs are similarly stored as callable fields. A method call foo.bar() is really just the variable access foo.bar, then a call on the resulting callable.

However, my language also has a typeclass system, like Rust. Unlike structs, traits have to “own” their functions, that is, they cannot simply be fields.

When performing the type checking, as struct members are conceptually fields on the struct, I need to do no extra work. Just access the field and then call it. As far as the type checker is concerned, when it sees a method call, it’s looking at a field access. However, trait methods are not defined as fields. The type checker can’t see that the access is actually a trait method call. How can I resolve this condundrum?

$\endgroup$
0

3 Answers 3

4
$\begingroup$

Different syntax

It wouldn't be unreasonable to require a different syntax for accessing fields and calling trait methods. One problem this are that a lot of languages use . for both, so that's what people are used to, and it's hard to come up with a different syntax that isn't weird-looking or verbose.

Requiring something like foo::bar for field accesses may be acceptable to you if you think your users won't be using field accesses too often (if your language has great pattern matching, for example).

$\endgroup$
4
$\begingroup$

UFCS

You can use something like UFCS. Special-case expression of the form foo.bar(...args). If your compiler encounters an expression of the form foo.bar(baz), but foo doesn't have a field called bar, make it look for a function bar in the current scope and treat the call as equivalent to bar(foo, baz).

$\endgroup$
5
  • $\begingroup$ Thing is, as explained in the question, the type checker doesn't know whether it's a function call or just a field access $\endgroup$
    – Seggan
    May 19, 2023 at 16:43
  • 2
    $\begingroup$ You'll just have to special-case expressions of that form (if you decide to use this approach). In my own language (unimplemented D:), I have a tree type called FnCall or something like that created in the parsing phase itself, and only later is it determined whether foo.bar(baz) refers to a field bar or a free function bar $\endgroup$
    – user
    May 19, 2023 at 16:45
  • $\begingroup$ There is no need to split your answer across multiple answers ─ when a question asks for a list of options, or pros/cons, it's fine (and good) for an answer to discuss more than one option or consideration. $\endgroup$
    – kaya3
    May 20, 2023 at 2:48
  • $\begingroup$ @kaya3 I thought it was decided on meta that we didn't want multiple answers combined into one (granted, I only suggested two options, not a whole list of them, but I figured I'd go with the consensus) $\endgroup$
    – user
    May 20, 2023 at 15:59
  • $\begingroup$ After writing my comment I realised that there were reasons the community might prefer separate answers ─ but I didn't find the specific case of multiple answers by the same author discussed on meta. So I started a discussion about that here ─ it seems there is no consensus yet but you may want to add your view there. $\endgroup$
    – kaya3
    May 20, 2023 at 16:02
2
$\begingroup$

In the course of writing this question, I found an answer. Feel free to add your own answers however.

This can be solved by simply making the trait implementation "add" its methods to the struct's fields. Therefore, as far as the type checker is concerned, the trait's methods are just another fields on the struct. This has another bonus as not calling the method (but just accessing it) returns the callable which can be used or stored for later.

$\endgroup$
1
  • $\begingroup$ Additional note: if different traits can have colliding method names, like in Rust, then this can still work, but the trait methods must only be added to the type's fields while the trait is in scope. $\endgroup$
    – kaya3
    Jun 20, 2023 at 16:34

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .