type foo = A of int * int | B of (int * int)
What is the difference between int * int and (int * int) there? The only difference I see is in pattern matching:
let test_foo = function
| A (f, s) -> (f, s)
| B b -> b
Is it just a syntactic sugar? How do you select which one to use? Is there any performance difference between these two forms?
Yes, there is a performance difference:
In memory
A (23, 42)will contain a tag identifying it as anAand the two integers 23 and 42.B (23, 42)will contain a tag identifying it as aBand a pointer to a tuple containing the integers23and42. So there will be one additional memory allocation when creating aBand one additional level of indirection when accessing the individual values inside aB. So in cases where you don’t actually use the constructor arguments as a tuple, usingAwill involve less overhead than usingB.On the other hand your
test_foofunction will create a new tuple every time it is called with anAvalue, but when it is called with aBvalue it will simply return the tuple that already exists in memory. Sotest_foois a cheaper operation forBthan it is forA. So if you’ll be using the constructor’s arguments as a tuple and you will do so multiple times for the same value, usingBwill be cheaper.So if you’re going to be using the constructor arguments as a tuple, it makes sense to use a constructor taking a tuple because you can get at the tuple using pattern matching with less code and because it will avoid having to create tuples from the same value multiple times. In all other cases not using a tuple is preferable because it involves less memory allocation and less indirection.