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 4b115da
Show file tree
Hide file tree
Showing 3 changed files with 85 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

Static constructor is the [Global Function](../code-sharing/global-function.md) 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](https://en.wikipedia.org/wiki/ML_(programming_language)) type langauges, you can think of primitives as similar to modules in [OCaml](https://ocaml.org/) and [F#](https://fsharp.org/).

Finally, here's our static constructor in action:

```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)
```
1 change: 1 addition & 0 deletions mkdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ nav:
- Notifier: 'code-sharing/notifier.md'
- Creation Patterns:
- Overview: 'creation/index.md'
- Static Constructor: 'creation/static-constructor.md'
- Supply Chain: 'creation/supply-chain.md'
- Data Sharing Patterns:
- Overview: 'data-sharing/index.md'
Expand Down

0 comments on commit 4b115da

Please sign in to comment.