Pattern Matching

Pattern matching is a powerful feature in type-c, it always to deconstruct variables, match algebraic types and overall provides a powerful control flow expression to smoothen code writing. I can't think of better words to describe Pattern Matching than how it is described in the OCaml Manual https://v2.ocaml.org/manual/patterns.html

Patterns are templates that allow selecting data structures of a given shape, and binding identifiers to components of the data structure. This selection operation is called pattern matching, its outcome is either "this value does not match this pattern", or "this value matches this pattern, resulting in the following bindings of names to values".

With that being said, pattern matching in type-c is heavily inspired by OCaml, hence you will find a great deal of similarities. First and foremost, any symbols that start with lowercase letter will be considered as binding symbols, and any symbols that start with uppercase letter will be considered as DataTypes. Hence its best is to follow Type-C convention of camelCase.

Variable Patterns

A pattern that employs a variable name matches any value, associating that name with the matched value. Similarly, the pattern represented by an underscore _ also matches any value but does not establish any name-binding

Patterns are linear, meaning a variable can only be bound once by a given pattern.

For such cases, you can use the if-guard:

Constant Patterns

A constant pattern matches any value that is equal to it in the sense of structural equality. The following are constant patterns:

Type Patterns

A type pattern matches any value of the specified type. This pattern is only applicable for instances of classes/interfaces and variants.

Note that null is used a value in pattern matching not a datatype.

Variant Pattern

Variant matching is slightly different from regular type matching since it can also be used to extract values from variants.

Array Pattern

Array pattern can be used to match an array based on its elements value and structure. An array pattern will automatically fail if the size of the array do not match the size of the bind variables used to construct the pattern. The over all structure of an array pattern is as follows: The array must start with n elements, and ends with tail.

In pattern matching, the symbol ... can be only be used in array matching, to fill the remaining elements of the array. Note that ...tail can and will fill an empty array.

Struct Pattern

Struct pattern can be used to match a struct based on its fields. Since structs' structure is static by default, it is not possible to perform pattern matching based on the structure.

You can also perform pattern matching on the struct elements:

Over all, struct patterns has the following structure: {<field_name>: <pattern>, ...}. The pattern applied to field can be any pattern, including variable, constant, type, variant, array, and struct patterns.

If Guard

Type-C, similarly to OCaml uses pattern-bound values in pattern matching and cannot directly insert variables into patterns for comparison. Hence if you want to compare a pattern with existing values say for the example you want to check if the first element of an array is equal to some variable x, then we will have to use the if-guard.

Inside the if-guard block, you have access to both the pattern-bound variables and the variables in the outer scope. The if-guard block is an expression, meaning it must return a value. If the if-guard block returns true, then the pattern is considered matched, otherwise it is not. Additionally, beware of shadowing, pattern-bound variables might shadow variables in the outer scope, inside your if-guard and pattern matching block.

camelCase

As mentioned earlier, camelCase is extremely important when performing pattern matching. When parsing the pattern matching expression, the compiler will need some hints before hand to expect either a datatype, or a binding variable. Since datatypes are supposed to Uppercase, type-c uses this to perform the appropriate parsing.

Just like the let .. in and if-else constructs, the match expression is optimized for use at the root level of an expression. When you need to use it within a larger expression, use parentheses to explicitly scope the match block.


Kudos! Keep reading!