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

Constrained primitive and string types #104

Closed
erikbra opened this issue Jan 28, 2015 · 7 comments
Closed

Constrained primitive and string types #104

erikbra opened this issue Jan 28, 2015 · 7 comments

Comments

@erikbra
Copy link

erikbra commented Jan 28, 2015

To avoid using a string parameter everywhere the value should be a string, but not any string, it would be useful to make a constrained version of a string, which only allows certain values.

The same thing would be true for primitive types like ints, doubles, etc.

People keep building CustomerId, AccountNumber, ZipCode, AddressLine, SSN, etc types, which are all basically constrained strings. It is definitely possible to work around this by creating types like this:

    class CustomerId
    {
        readonly string _value;
        public CustomerId(string value)
        {
            Validate(value);
            _value = value;
        }

        private static void Validate(string value)
        {
            if (value.Length != 9)
            {
                throw new ArgumentOutOfRangeException(value, "CustomerId length must be 9.");
            }
        }

        public override string ToString()
        {
            return _value;
        }

        public static implicit operator CustomerId(string value)
        {
            return new CustomerId(value);
        }

        public static implicit operator string(CustomerId cid)
        {
            return cid._value;
        }
    }

And, of course generalize it into a ConstrainedString with a pure virtual Validate function.
However, it would be nice to have language support for this, as I see far too often people using strings when they don't accept any string. If we get language support for the concept, it would be easier to create domain types and get those checks compile-time, and not runtime.

Not sure of the best syntax, but one proposition would be to extend the generic syntax, like this:

    class CustomerId<T> where T: string { s => s.Length == 9 }
    {
    }
    class AccountNumber<T> where T: string { s => IsValidAccountNumber(s) }
    {
        public static bool IsValidAccountNumber(string s) {
            return (s % 11 == 0); // Arbitrary validation logic
        }
    }

and, similarily with primitive types:

    class Age<T> where T: int { i => i >= 0 &&  i < 130 }
    {
    }
    class AngleDeg<T> where T: double { d => d >= 0 &&  d <= 360 }
    {
    }

Etc, etc. This would make the language richer, and, maybe more checks could be performed compile-time (Roslyn to the rescue).

@AdamSpeight2008
Copy link
Contributor

Sounds similar to Pseudo-Inheritance

@mikedn
Copy link

mikedn commented Jan 28, 2015

Using a class can be problematic from a performance point of view. A struct is usually better but it too has some drawbacks. See #58 too.

@erikbra
Copy link
Author

erikbra commented Jan 28, 2015

@mikedn Yes, #58 is definitely similar, even though I wouldn't have proposed excactly that solution. If you use the first suggestion, to just create an alias for a type, you don't get the constraint bit. If you use the second, which is similar to a class definition, it really just looks as if you wished string was inheritable.

Whether it is implemented on classes of structs or both I don't care. But I see good uses for both constrained strings (which is a class) and primitive types.

@erikbra
Copy link
Author

erikbra commented Jan 28, 2015

@AdamSpeight2008 Yes, maybe similar, but Pseudo-Inheritance would have had to be extended to get the constraint part. I would like a stronger concept than what an Enum is to an int (which is not really a constraint at all, just a glorified alias ;))

@AdamSpeight2008
Copy link
Contributor

@erikbra You seen my idea for traits in #98?

@erikbra
Copy link
Author

erikbra commented Jan 28, 2015

@AdamSpeight2008 Saw it now. You didn't mean that traits could be used to solve my suggestion for constrained basic types, did you? I read about traits in your links, and I don't know if I like them or not. Maybe I'm just not smart enough to appreciate them. I think delegating the functionality to a separate class and calling it from both other classes will achieve the same purpose. and, I really didn't like the "include any arbitrary lines of code in my class" feel it had to it. Maybe just a matter of taste. I would prefer putting the "trait" in another class, and instanciating and calling that if you need it. But I am very open to being missing out on something here .)

@MadsTorgersen
Copy link
Contributor

This seems to enter the field of dependent types, which is murky and fraught with compile time evaluation.

The scenarios seem better addressed with some notion of contracts, e.g. #119.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

7 participants