Doesn’t it make sense if I do
type Point =
struct
val Row: int
val Column: int
new (row, column) = if row >= 0 && column >= 0 then { Row = row; Column = column }
else failwith "Cooridinators must be non-negative!"
// This is not a valid object construction
static member (+) (x: Point, y: Point) = Point (x.Row + y.Row, x.Column + y.Column)
static member (-) (x: Point, y: Point) = Point (x.Row - y.Row, x.Column - y.Column)
static member (*) (x: Point, a) = Point (x.Row * a, x.Column * a)
static member (*) (a, x: Point) = Point (x.Row * a, x.Column * a)
end
If it was a class then maybe I can raise exception during the do binding, but in a structure there is no do, what am I supposed to do?
I figured out that it is possible to add another constructor after failwith to get around this, but it raises another question, how can I call the implicit constructor? Do I have to construct it explicitly first like
new () = { Row = 0; Column = 0}
// Error structs auto supports a default constructor
If i simply do this using the default constructor
new (row, column) = if row >= 0 && column >= 0 then { Row = row; Column = column }
else
failwith "Cooridinators must be non-negative!"
new Point () // error
It appears to me that Point () returns a unit rather than Point?
I think the F# compiler complains because constructors should always have a structure:
So, the part that initializes the fields cannot be nested under
ifor inside any other expression. You can throw exceptions either before the initialization or after (if you addthenkeyword). (This matters for classes with inheritance, but I don’t think it makes any difference for structs.)So, one way to write the code is to write:
Note that I had to negate the condition, because you need to specify the case when you want to throw the exception (rather than saying when you can construct the object). The other alternative would be: