Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

filter valid values in function declaration #69

Open
Binto86 opened this issue Jul 18, 2022 · 4 comments
Open

filter valid values in function declaration #69

Binto86 opened this issue Jul 18, 2022 · 4 comments
Labels
Language idea One single idea which may be a start of a design document

Comments

@Binto86
Copy link
Contributor

Binto86 commented Jul 18, 2022

You may want to throw an exception when value inputed into your function doesn't match what you want (value is null is the most common example). In c# you would problably need to manually check if value matches this rule using ifs and throwing exception in the function.
It would be nice to be able to specify some structure that could throw on the method call without you needing to manually check the value.
I think that this could be solved by new structure rule.
I am thinking of this syntax:

rule notnull(value: string)
{
    if(value is null)
    {
        throw new ArgumentNullException("value");
    }
}

func method(x:string is notnull)
{
     //your code where you know x is not null
}

The rule structure would need to have at least one throw statement an would accept only one parameter.
Question is how to specify that you want certain rule to be aplied to your parameter, i used is keyword, but thats probably not the best way.

@LPeter1997
Copy link
Member

This is called Design by Contract, and the previous proposal of C#s !! was essentially a special case for a not-null precondition for that. They are a perfect use-case for decorators I believe. It has the advantage that it requires no additional language elements. A made-up implementation of your example, partially based on the metaprogramming issue:

#[macro(decorator)]
func PreCondition(args: MacroArgs, target: SyntaxTree): SyntaxTree
{
    val target = target.cast[SyntaxTree.FuncDeclaration];
    val condition = parse_expr(args[0]);
    return quote!{
        #(target.signature)
        {
            if not (#(args.condition)) throw ArgumentException();
            return { #(target.body) };
        }
    };
}

An example usage could be:

#[PreCondition(n > 0)]
func log_positive(n: int32) = Console.WriteLine(n);

Which would be transformed by the macro to

func log_positive(n: int32)
{
    if not (n > 0) throw ArgumentException();
    return { Console.WriteLine(n) }; // Looks odd but it's OK, returns unit
}

@Binto86
Copy link
Contributor Author

Binto86 commented Jul 18, 2022

That looks good to me

@jl0pd
Copy link

jl0pd commented Jul 19, 2022

This can be achieved with active patterns. F# example

let (|NonNull|) x =
    if isNull x then
        nullArg "x"
    else
        x
        
let f (NonNull x) = // x is never null
    printfn "%A" x

It's a simple and very powerful tool, which can be used anywhere, where pattern matching is allowed. With addition for CallerArgumentExpression it's even can capture real argument name.

Research document: https://www.microsoft.com/en-us/research/wp-content/uploads/2016/02/p29-syme.pdf

@LPeter1997
Copy link
Member

While active patterns are cool and we have discussed them related to the pattern matching issue, they will probably not make it into the language, as we are planning to expose a pattern matching protocol that would be a more general tool. I believe this case is more neatly solved with decorators, but that's just my 2 cents.

@LPeter1997 LPeter1997 added the Language idea One single idea which may be a start of a design document label Jul 20, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Language idea One single idea which may be a start of a design document
Projects
None yet
Development

No branches or pull requests

3 participants