dotnet / csharplang

The official repo for the design of the C# programming language
11.54k stars 1.03k forks source link

Methods Aliases #1525

Closed ghost closed 5 years ago

ghost commented 6 years ago

While I was working on improving Verex (VerbalExpressions), I faced the problem of choosing the precise name for the functions that generates the regex patterns. I had to define the same function more than once to gave it more than one name, trying to make verbal expressions as familiar as possible for each user. For example:


        public Verex AtomicGroup(Verex Expr)
        {
            string s = $"(?>{Expr.ToString()})";
            return Add(s);
        }

        public Verex Greedy(Verex Expr)
        {
            return AtomicGroup(Expr);
        }

        public Verex Nonbacktracking(Verex Expr)
        {
            return AtomicGroup(Expr);
        }

So, I wondered: Why can't I just define aliases for methods? If I had some AliasesAttribute, the last code would be:

[Aliases(Nonbacktracking, Greedy)]
public Verex AtomicGroup(Verex Expr)
{
   string s = $"(?>{Expr.ToString()})";
   return Add(s);
}

Then C# should allow to call this function by any of the names: AtomicGroup, Nonbacktracking or Greedy. The concept of aliases is not new. We already define aliases for namespaces and static classes (or non-static classes in VB.NET). We also define aliases for API functions. So, I will be bold and go furthermore and hope the user be able to define a new alias if he is not comfortable with mine, without having to create a wrapper (a new class that contains new methods with the new names and all they do is calling the original methods)! Maybe he just write: #define Verex.AtomicGroup as NoBacktrack; So, he can just use Verex.NoBacktrack!

Before asking: I don't know who will or will not need such a thing. I just ran into this situation and shared it with you.

svick commented 6 years ago

I don't see how this would be a worthwhile addition to the language. You already have a simple and fairly short syntax for declaring such aliases by using expression-bodied methods, e.g.:

public Verex Greedy(Verex Expr) => AtomicGroup(Expr);

public Verex Nonbacktracking(Verex Expr) => AtomicGroup(Expr);

This also doesn't seem like a common need to me, since I think having many such synonyms would be frowned upon by most API designers.

As for user defined aliases, we already have extension methods. We don't have static extension methods, and I do think those would be useful, but that's a different proposal (https://github.com/dotnet/csharplang/issues/192).

bondsbw commented 6 years ago

Also

public Func<Verex, Verex> Greedy => AtomicGroup;
public Func<Verex, Verex> Nonbacktracking => AtomicGroup;

Which looks even better if we get #269:

public (Verex => Verex) Greedy => AtomicGroup;
public (Verex => Verex) Nonbacktracking => AtomicGroup;
bondsbw commented 6 years ago

Even more succinct (if AtomicGroup is static):

public (Verex => Verex)
    Greedy = AtomicGroup,
    Nonbacktracking = AtomicGroup;
ghost commented 6 years ago

Thanks for the info. Can't we just write: public Greedy => AtomicGroup; So it is translated to: public Verex Greedy(Verex Expr) => AtomicGroup(Expr); :)

bondsbw commented 6 years ago

That requires type inference for locals (var fields/properties/methods), which has been discussed elsewhere and seems unlikely.

ghost commented 6 years ago

What about this public delegate Greedy = AtomicGroup; There is no need to specify params and return type, because it is already declated in Atomicgroup. Besideds, this is not local. It is defined at the class level.

ghost commented 6 years ago

The only working code right now is: public Func<Verex, Verex> Greedy => AtomicGroup; But it will not be easy to understand by kust a look from the user. This is still easier to read and is not longer!: public Verex Greedy(Verex Expr) => AtomicGroup(Expr);

HaloFour commented 6 years ago

I can't see a specialized syntax that would be warranted for a feature like this which would hopefully be very rarely used. But I could see it enabled by syntax for delegation/forwarding, e.g.:

public class Foo : IDisposable {
    private readonly IDisposable child;

    // forward call to child
    public void Dispose() = child.Dispose
    // forward call to self
    public void Close() = this.Dispose
}