Skip to content

Commit

Permalink
Add "static constructor" pattern
Browse files Browse the repository at this point in the history
  • Loading branch information
SeanTAllen committed Jan 20, 2024
1 parent a0ce4b3 commit aff1734
Show file tree
Hide file tree
Showing 2 changed files with 84 additions and 0 deletions.
1 change: 1 addition & 0 deletions .spelling-wordlist.txt
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ mixin
mixins
namespace
natively
OCaml
oof
ponylang
preallocate
Expand Down
83 changes: 83 additions & 0 deletions docs/creation/static-constructor.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
---
hide:
- toc
---

# Static Constructor

## Problem

You want to construct an object or return a meaningful error message. 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 return as we jump to the nearest error handler.

```pony
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:

```pony
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`.

```pony
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

Primitives serve a number of roles in Pony. Similar to modules in [OCaml](https://ocaml.org/) and [F#](https://fsharp.org/), Pony's primitives are a great way to group together stateless "like functions". In general, 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.

Here, our primitive `FooConstructor` has a single function `apply` that is used to try and construct a `Foo` or if its construction prerequisites aren't met, return an informative message.

```pony
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)
```

Static constructor is the [Global Function](../code-sharing/global-function.md) pattern applied to object construction.

0 comments on commit aff1734

Please sign in to comment.