Skip to content

(Proposal) Match Expression #191

@AdamSpeight2008

Description

@AdamSpeight2008

Match Expression

This proposal is separated out from #180. The approach to the syntax is an alternative to the one proposed by @MadsTorgersen

A match expression block is an expression as it permits uses in situations that switch can not be used. For example in-conjunction with a return

return match( ... ) { | _ => ... }

or an 'await' this needs further investigation

var result = await match( ) { };
  • |
    donates the start of a match clause
  • into
    allow you to introduce new variables into the scope (of this match clause), or reuse existing in scope variables.
    ** := is for introducing a new variable into scope.
  • when
    is for specifying that this match clause is considered if the predicate is satisfied.
  • => this doesn't indicate the the expression after is a lambda function, it just reusing an existing symbol as it's is close to what you use for lambda. Eg multiple statements / expression are required to be enclosed inside braces { ... }. Not needing a return for simple single expressions.
    The code called when the match clause is satisfied could be an expression, a statement or an exception.You can't intermingle expression and statements.
    Eg
match ( x ) with
{
  | 0 => Console.WriteLine("Zero");
  | 1 => return "One"; // Error not a statement;
  | _ => Throw New Exception("FUBAR");
}


match ( x ) with
{
  | 1 => return "One";
  | 0 => Console.WriteLine("Zero"); // Error not an expression
  | _ => Throw New Exception("FUBAR");
}

The rationale for into before when is that is allows the variable just introduced to be used with the predicate of the of the guard expression (when).

... is being use in the following examples as a place-holder for some code.

Default Clause

Every match is required to have default clause, which is used if non of the other clause are satisfied. Examples will use | _ => to represent this. If all of args in the "target" are wildcards this is also consider a default clause. A default clause most also have no guards, so it can catch all possibilities..

Examples

match ( e , a ) with
{  
  | ( null, null ) => ... ;
  | ( _ , _ ) into 
       {l:= a.Left as IdentifierName;
        r:= a.Right as IdentifierName;
       } => match (l,r) with
            {
              | (null,null) =>  ... ;
              | ( _ , _ ) when (a.Name.name == r.Name.name) => ... ;
              | _ => ... ;
            };
  | _ => ... ;
}
try
{
  var res = match( l, op , r ) with
            { 
              | ( _ ,'+', _ ) => ... ;
              | ( _ ,'-', _ ) => ... ; 
              | ( _ ,'*', _ ) => ... ;
              | ( _ ,'/'. _ ) => ... ;
              | ( _ , _ , _ ) => throw new NotSupported(); // Also the default clause.
            }
catch (ex) when NotSuppored
{
  ...
}
match type ( o ) with
{
  | ( String ) into s when (s != null) => ;
  | ( Short  ) into s when (s >= 0 ) => ; // not an error 
  // ...
}

Grammar

match_expr     ::= "match" match_category? '(' match_source ')' "with"
match_source   ::= source (',' source)*
match_body     ::= '{' clause* default_clause '}'
match_category ::= match_type
match_type     ::= "type"
clause         ::= '|' target into? when? result
default_clause ::= '|' '_' "=>" expr ';'
target         ::= target_part | '(' target_part ')' | '(' target_part (',' target_part)+ ')'
target_part    ::= 
target_wild    ::= '_'
into           ::= "into" '{' into_vars '}' 
into_vars      ::= into_var ( into_var )*
into_var       ::= in_scope | in_var 
in_scope       ::= identifier ';' 
in_var         ::= identitfier ":=" expr ';'
when           ::= "when" predicate
predicate      ::= 
result         ::= "=>" expr ';'
expr           ::=

How the your code looks when using the form being proposed is clean looking and fit in well is existing C# style. It's not too far from existing style to be jarring, when creating the examples it felt (to me) very natural.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions