gracelang / language

Design of the Grace language and its libraries
GNU General Public License v2.0
6 stars 1 forks source link

how to write alias clauses to cope with overriding on arity #37

Closed kjx closed 8 years ago

kjx commented 8 years ago

Currently, without overloading by arity, we write

use someTrait
     alias other()name() = foo()bar()

which ignores arity, and lets programmers (particularly novices) ignore arity. If someTrait has more than one foo()bar() method, we don't know which method to rename.

Options like

use someTrait
     alias other(1)name(2) = foo(2)bar(1)
     alias other(_)name(_,_) = foo(_),bar(_,_) 
     alias other(x) = foo(y)bar("bar")

are either ugly, syntactically encourage options we don't want, and all make clear the potential for overriding on arity when really I'd really like to hide that for as much and as long a possible.

If we have to override on arity, I propose three evil rules cases:

  1. write arities only on the RHS (renaming cannot change arities or redistribute arguments amongst parts)
  2. if there is only one method in the trait, omit arities even on the RHS
  3. trailing ()s can always be omitted
    use someTrait
         alias other()name() = foo(2)bar(1)
         alias myLocalName = nonOverriddenMethodInTheTrait 
         alias myMulti()LocalName() = anotherNonOverridden()MethodInTheTrait() 

This means that, up until standardGrace at least, programmers can totally ignore overloading on arities. We hates them my precious. Hates them.

Ok: thinking a bit more, how about just one rule (the "Neutral Bomb" rule)

  1. never write arities. aliasing makes new names, leaves arguments & arities exactly the same.

We keep exactly the same syntax we have now, and simply "coherently" rename all overloaded methods in the same way. That's it. That's all. Hah. You know what, if we must do this, that's probably my preference.

kjx commented 8 years ago

to be clear: what i now propose is the "Neutron Bomb" rule

  1. never write arities. aliasing makes new names, leaves arguments & arities in exactly the same places.

We keep exactly the same syntax we have now, and simply "coherently" rename all overloaded methods in the same way.

apblack commented 8 years ago

This issue is about how to name methods.

We name methods in four places:

  1. in method declarations
  2. in type literals
  3. in alias clauses
  4. in requests of the method (including requests of operators)

We have taken pains so far that (1) and (2) are as consistent as possible, e.g., we allow types and identifiers in argument lists in both. (4) is different, both necessarily (because requests take argument expressions, while definitions declare parameter variables), and arbitrarily. (Think of prefix methods).

Be that as it may, it seems to be that we should not introduce further variety, but we should use for (3) the same conventions that we have used for (1) and (2).

This would mean that just as we declare

method myMulti(a)LocalName(b)

we should write myMulti(a)LocalName(b) in the alias clause too. And we should write that on both sides of the equals sign, because both names are just names, not requests. (in other words, the parameter identifiers are defining occurrences)

As defining occurrences of names that are never used, the parameters in method names in an alias clause can always be replaced by _, if the programmer wants. This is probably a good practice, because writing

    alias myNew(a)LocalName(b) = myMulti(b)LocalName(a)

might confuse a reader. So it's better to write

    alias myNew(_)LocalName(_) = myMulti(_)LocalName(_)

As for overloading by arity, that's resolved in the same way that it's resolved in (1), (2), and (4): by counting commas. So

    alias minimum(_, _) = min(_, _)
    alias my(_)new(_)localName(_) = old3ParamName(_, _, _)

I don't see a need to make the language larger or more complex to deal with this particular case. Aliases, like super, will be used rarely, and probably not at all by novices. The syntax with the underscores (or parameter names) is a bit cumbersome, but it makes it pretty clear what going on, which rules for automatically capturing some related set of names don't.

With regard to the final alias above, note that now we have got rid of variable arity methods, our parameter and argument lists are just like every other languages': they are lists. They no longer have to be lists of lists. So a method that takes 3 parameters is just that. Those of us who have to define or use a Foreign Function Interface will be pleased. I don't see any reason to forbid an alias from introducing additional name parts.

kjx commented 8 years ago

Be that as it may, it seems to be that we should not introduce further variety, but we should use for (3) the same conventions that we have used for (1) and (2).

This is a very strong argument for doing it this way - keeping the type syntax. Perhaps we should mandate only underscores in these type-declaration-like contexts?

KimBruce commented 8 years ago

I'm not sure I understand the import of the "only" in your sentence above. I'd give the programmer a choice of underscores or parameter name (as we do for types). Allowing names makes it easier to write better comments.

I'd like to adopt Andrew's suggesting of adopting the same rules as (2) above.

kjx commented 8 years ago

I'm not sure I understand the import of the "only" in your sentence above. I'd give the programmer a choice of underscores or parameter name (as we do for types).

Ignore me: I meant not giving them that choice, but that means we have gratuitous asymmetry again.

I'd like to adopt Andrew's suggesting of adopting the same rules as (2) above.

OK. Happy with that.

apblack commented 8 years ago

Looks like we are agreed to use the same notation for names in types, method declarations and aliases.

kjx commented 8 years ago

drafted - https://github.com/gracelang/language/blob/portland-james/spec.md#method-names