Hacker News new | past | comments | ask | show | jobs | submit login

The most obvious approach would be to repurpose C++ syntax, since it's already been around for a while, and C# syntax is generally pretty close to C++ in many respects. So:

  public SomeMethod(bool b) -> (string name, int id) { ... }
However, this may be undesirable due to confusion with => for lambdas and expression-bodied methods, especially in:

  public SomeMethod(bool b) -> (string name, int id) => ...
: is the next obvious candidate, and would unify the syntax with TypeScript and many other languages. But given that it's already used for labels and named arguments, I'm not sure there's enough room there to reuse it also for types.

:: is another decent choice in terms of familiarity coming from other languages (Fortran, Haskell etc). But, unfortunately, it's already taken for extern alias, and I don't think this could be easily disambiguated in many contexts.

Now, if this is narrowly scoped to method return type only (i.e. we're not trying to invent a syntax that could later be used in a similar way to swap the type and the name in other places, like arguments and variables), and only as a fallback for when the usual "Type Name" arrangement has poor readability, perhaps take a hint from Ada and reuse "return"?

  public SomeMethod(bool b) return (string name, int id) { ... }
A tad verbose, but if it's intended to be used sparingly, primarily with tuple-returning methods and deeply nested generics, I think that's okay - tuples themselves are pretty verbose when components are named.

Or maybe borrow "as" from VB? It looks like it could be extended to other kinds of declarations in the future in a straightforward manner, without conflicting with its existing use for casts:

  // Just for method return types
  public SomeMethod(bool b) as (string name, int id) { ... }

  // For everything
  public SomeMethod(b as bool) as (name as string, id as int) {
    var x as float;
    TryFoo(out var y as bool);
    ...
    switch (obj) {
      case foo as Foo:
        ...
    }
  }



I like the as syntax, it may conflict with casting though when used on variables.

    public SomeMethod(bool b) -> (string name, int id) { ... }
When was this added to c++? I think I need to brush up on my lower level skills.


With regards to "as" conflicting, I think it shouldn't be a problem because the cast operator is binary. So if you already know that something is a declaration, the current token is the identifier that's being declared (or closing parenthesis of the parameter list), and the following token is "as", it cannot be a valid expression. Consider:

  var x as int;
"var" makes it a declaration, so "x" is the identifier, and "as" has to be the type specifier.

  var x = y as int;
"=" clearly separates the identifier from the initializer, and the latter is an expression, so "as" is the cast operator.

Similar reasoning applies to other places where the two can appear - function parameter list, return type, field and property declarations etc.

So far as I can tell, by the time we get to the point where "as" would be used to specify the type of the declared entity, we will already know that it's a declaration, and that the only other token that can follow in existing grammar is "=", "{", or "=>" (for variable and field initializers and default parameter values, property getters and setters, and lambdas and expression-bodied members, respectively), and none of these start an expression. In all other contexts, "as" would be an operator.


It was added in C++11 when they added decltype(), so that you could reference arguments when computing return type. It's slightly different though, in that you need to specify the return type in the usual position as "auto" first, and then you can use "->" after the parameter list. So:

  template<typename A1, typename A2>
  auto foo(A1 a1, A2 a2) -> decltype(a1 + a2) {
    return a1 + a2;
  }




Guidelines | FAQ | Support | API | Security | Lists | Bookmarklet | Legal | Apply to YC | Contact

Search: