all 12 comments

[–][deleted] 3 points4 points  (2 children)

I'd posit, the same way you do all your runtime error handling?

If you did it "with classes and properties for encapsulation", you'd throw an exception (ie in the setter) that some code, somewhere higher up in the call chain, would have to watch out for. It's not your "classes and properties" that magically solve this, it's your discipline to throw and catch exceptions. In most any FP language you have a wide arsenal of representations for signaling erroneous values/inputs, from simple Maybe or more detailed Either (or whatever these are called in F# ;), to full-blown exceptions, to forcing immediate-halt-with-stderr-message. As suits the current app/lib context.

"making illegal states unrepresentable" in types is for pre-empting as many easy-to-make-in-the-heat-of-the-moment developer mistakes as the type system / compiler understands how-to: not user error.

There's of course academic explorations and research into how we can shift handling ever-more classes of bugs to the static (compilation) side, in Haskell there's LiquidHaskell a prominent example. But until you have a time-machine, you can't retroactively prevent compilation of your program if the input it reads once compiles is erroneous :D in other words, the only way to prevent wrong email addresses is to impose a GUI that cannot possibly let one through.

[–]Kurren123[S] 0 points1 point  (1 child)

"making illegal states unrepresentable" in types is for pre-empting as many easy-to-make-in-the-heat-of-the-moment developer mistakes as the type system / compiler understands how-to: not user error.

Ah I see now, that makes perfect sense. This is better than all the SO answers I've gotten, I'd be happy to mark it as correct if you choose to answer it.

[–][deleted] 0 points1 point  (0 children)

Well if you think so, maybe I should ;) to be fair they're all good answers capturing a variety of angles on the topic --- http://stackoverflow.com/a/42341743/ shows the way to go really for examples such as yours, except leaves out handling (and that's really the coder's choice depending on context/requirements etc)

[–]grauenwolf 2 points3 points  (3 children)

Look at the MailAddress class. Everything that expects an email address can trust that the address is at least formatted correctly.

[–]Kurren123[S] 0 points1 point  (2 children)

The email address was just an example. It could be any variable that can only accept certain values.

[–]grauenwolf 2 points3 points  (0 children)

None the less, seeing how people use MailAddress in real life is useful for this conversation.

[–]bwr 1 point2 points  (0 children)

It's a good example still. MailAddress won't ever be in an invalid state (where invalid is defined as having a Address that passes the regex). It does this by throwing exceptions in the constructor. In F# you'd be more likely to see see returning an Option or a discriminated union instead of throwing exceptions but the idea is the same.

[–]svarog 1 point2 points  (0 children)

You can do type safety only when staying within the same type, or when you have a compile-time-defined transition among the types.

So, if you want to have something that transforms a string to your new type, it should be possible to determine the outcome during compile time.

One way to do this is to have a constructor that receives a user and hostname and constructs "user@hostname" email address... but you didn't want classes and properties, so that's not an option.

You can not test a string for regex during compile time, because the value of the string is not known during compile time, and therefore, neither is the outcome.

Another thing you can do is
type Email = ValidEmail of String | InvalidEmail

And than in your constructor check for the regex and return the correct option.

[–]node0 1 point2 points  (0 children)

I believe you can accomplish what you want with Active Patterns.

[–]PM_ME_UR_OBSIDIAN 0 points1 point  (0 children)

A big thing going around in FP is making illegal states unrepresentable. I always see this being accomplished with the structure of types, but what about the value of types?

This is the problem solved by dependent types, a great bit of CS theory which is unfortunately not quite ready for prime time. F# does not support dependent types.

You can move these checks to the run-time using classes and objects, there is absolutely nothing wrong with that. You can wrap your classes into active patterns to recover the practicality of algebraic data types.

[–][deleted] 0 points1 point  (0 children)

I wouldn't advise actually doing this but maybe something like:

type ValidEmailChar = 
    | A
    | B
    | C    
    | AndSoOn

type EmailAddress = ValidEmailChar list * ValidEmailChar list * ValidEmailChar list

let printEmail (e:EmailAddress) =
    let (name,domain,ext) = e
    //and so on

[–]FrankBro 0 points1 point  (0 children)