"#firstName" << "Kevin" "#firstName" == "Kevin"That code is the same as this code written with the Coypu web testing library:
browser.FillIn("#firstName").With("Kevin") browser.FindField("#firstName").Value.ShouldEqual("Kevin")As you've likely deduced, the "<<" operator has been overridden to lookup the field and set it's value, while the "==" operator has been overridden to lookup up the field and assert on it's value.
In this case, both of these operators do exist already in F#, but they obviously aren't usually used to drive a web browser. So this is a powerful use of operator overloading. But F# allows you to define custom operators that have no definition in F# as well. They can be any combination of a certain set of characters.
For example, there is no "=~" operator in F#, but you could define one to do a regex match as follows:
open System.Text.RegularExpressions let (=~) input pattern = Regex.IsMatch(input, pattern)And you'd use it like:
"some input" =~ ".*input"And you could also define one that is case insensitive:
let (=~*) input pattern = Regex.IsMatch(input, pattern, RegexOptions.IgnoreCase)These operators are not overloaded, they're just custom defined.
There is clearly a tradeoff here between explicit code and concise code. Look back at the first example from Canopy again. If you knew that was web testing code, and you recognized "#firstName" as a css selector, you would probably figure out what it was doing. And this conciseness is going to be really nice in a situation where you're executing the same type of operations over and over and over again (say, like, in a Selenium web test!). So while there's no mistaking what the Coypu code is doing, I'd rather write the Canopy code!
However, in the regular expression example, since =~ and =~* are not part of the language, how would you know what they do. Certainly there's a similarity to ruby, but I've never seen a =~* operator. So introducing stuff like this to your code base runs the risk of making your code harder to understand.
In the end, I think it's an awesome feature to have at your disposal. And I think a good rule of thumb is to be willing to try some custom operators when you have a high and dense repetition of operations. That is, it's not a one off operation, or it's not used always by itself in far flung sections of code.
In any case, this another powerful, and very neat, feature of F#.