Static Constructor¶
Problem¶
You want to construct an object or return a meaningful error message if the object can’t be constructed. For example, if a parameter is supposed to be in the range of 1 to 10, but 12 was passed. You’d like to return an error that “12 is out of range” instead of constructing the object. Unfortunately, in Pony there’s no way to do that. Pony constructors always return an initialized instance of their class unless the constructor is partial in which case nothing is returned as we jump to the nearest error handler.
class Foo
// Always returns a foo
new create() => None
// Sometimes returns a foo
new perhaps(a: Bool) ? =>
if not a then
error
end
What you would like to do instead is:
class Error
let msg: String
new create(m: String) =>
msg = m
class Foo
// return a Foo or Error message
new create(a: Bool): (Foo | Error) =>
if not a then
Error("Can't build Foo that way")
else
this
end
Solution¶
Use a primitive
.
class Error
let msg: String
new create(m: String) =>
msg = m
class Foo
new create() => None
primitive FooConstructor
fun apply(a: Bool): (Foo | Error) =>
if not a then
Error("Can't build a Foo that way")
else
Foo
end
Discussion¶
Static constructor is the Global Function pattern applied to object construction. As we discussed in Global Function, Pony’s primitives are a great way to group together stateless “like functions”. If you are looking to do anything that might be classified as a static function or a utility function in another language, you probably want to use a primitive in Pony.
If you have an background in ML type languages, you can think of primitives as similar to modules in OCaml and F#.
Finally, here’s our static constructor in action:
actor Main
new create(env: Env) =>
match FooConstructor(true)
| let f: Foo =>
// ToDo: do something with Foo
None
| let e: Error =>
env.err.print(e.msg)
end