Multiton
The multiton pattern is a design pattern which generalizes the singleton pattern. Whereas the singleton allows only one instance of a class to be created, the multiton pattern allows for the controlled creation of multiple instances, which it manages through the use of a map.

You are encouraged to solve this task according to the task description, using any language you may know.
- Description
- Task
Implement a basic Multiton class or other structure and test that it works as intended. If your language does not support the object oriented paradigm, then try to emulate a multiton as best you can with the tools available.
If your language supports multithreading, then you may optionally implement a thread safe variant as well.
- Related task
#include <iostream>
#include <unordered_map>
#include <mutex>
#include <memory>
enum class MultitonType {
ZERO,
ONE,
TWO
};
class Multiton {
public:
// Thread-safe method to get instance
// Returns nullptr if the type is not found in the map
static Multiton* getInstance(MultitonType type) {
std::lock_guard<std::mutex> lock(mutex_);
auto it = instances_.find(type);
return (it != instances_.end()) ? it->second.get() : nullptr;
}
// Override toString equivalent
std::string toString() const {
std::string typeStr;
switch (type_) {
case MultitonType::ZERO: typeStr = "ZERO"; break;
case MultitonType::ONE: typeStr = "ONE"; break;
case MultitonType::TWO: typeStr = "TWO"; break;
}
return "This is Multiton " + typeStr;
}
// Overload << operator for easy printing
friend std::ostream& operator<<(std::ostream& os, const Multiton& multiton) {
os << multiton.toString();
return os;
}
private:
// Private constructor to prevent direct instantiation
explicit Multiton(MultitonType type) : type_(type) {}
MultitonType type_;
// Thread-safe static members
static std::unordered_map<MultitonType, std::unique_ptr<Multiton>> instances_;
static std::mutex mutex_;
// Static initialization helper
static bool initializeInstances();
static bool initialized_;
};
// Static member definitions
std::unordered_map<MultitonType, std::unique_ptr<Multiton>> Multiton::instances_;
std::mutex Multiton::mutex_;
bool Multiton::initialized_ = Multiton::initializeInstances();
// Initialize all instances (equivalent to Java's static block)
bool Multiton::initializeInstances() {
instances_[MultitonType::ZERO] = std::unique_ptr<Multiton>(new Multiton(MultitonType::ZERO));
instances_[MultitonType::ONE] = std::unique_ptr<Multiton>(new Multiton(MultitonType::ONE));
instances_[MultitonType::TWO] = std::unique_ptr<Multiton>(new Multiton(MultitonType::TWO));
return true;
}
int main() {
Multiton* alpha = Multiton::getInstance(MultitonType::ZERO);
Multiton* beta = Multiton::getInstance(MultitonType::ZERO);
Multiton* gamma = Multiton::getInstance(MultitonType::ONE);
Multiton* delta = Multiton::getInstance(MultitonType::TWO);
std::cout << *alpha << std::endl;
std::cout << *beta << std::endl;
std::cout << *gamma << std::endl;
std::cout << *delta << std::endl;
// Verify that alpha and beta point to the same instance
std::cout << "alpha == beta: " << (alpha == beta ? "true" : "false") << std::endl;
return 0;
}
- Output:
This is Multiton ZERO This is Multiton ZERO This is Multiton ONE This is Multiton TWO alpha == beta: true
Functional languages encourage the use of pure functions and immutable data structures, which naturally reduce the need for managing object lifecycles, F# is multiparadigm so lets try.
// Multiton. Nigel Galloway: April 1st., 2026
type Multitons= |N|I|G|E|L
module Multiton =
let private n = Lazy.Create(fun() -> printfn "initializing";"N")
let private i = Lazy.Create(fun() -> printfn "initializing";"I")
let private g = Lazy.Create(fun() -> printfn "initializing";"G")
let private e = Lazy.Create(fun() -> printfn "initializing";"E")
let private l = Lazy.Create(fun() -> printfn "initializing";"L")
let GetInstance=function N->n.Force|I->i.Force|G->g.Force|E->e.Force|L->l.Force
let n1=Multiton.GetInstance N
let n2=Multiton.GetInstance N
let g1=Multiton.GetInstance G
let g2=Multiton.GetInstance G
printfn "%s" (n1())
printfn "%s" (n2())
printfn "%s" (g1())
printfn "%s" (g2())
- Output:
initializing N N initializing G G
Dim Shared As String permitido(2)
permitido(0) = "zero"
permitido(1) = "one"
permitido(2) = "two"
Dim Shared As Any Ptr instancias(2)
Type multiton
id As String
Declare Constructor(id As String)
End Type
Constructor multiton(id As String)
Dim k As Integer = -1
For i As Integer = 0 To Ubound(permitido)
If permitido(i) = id Then
k = i
Exit For
End If
Next
If k = -1 Then
Print "not permitido"
End 1
End If
If instancias(k) = 0 Then
this.id = id & "_" & Str(Int(Rnd * 999))
instancias(k) = @This
Else
This = *Cast(multiton Ptr, instancias(k))
End If
End Constructor
Dim a As multiton = multiton("zero")
Dim b As multiton = multiton("one")
Dim c As multiton = multiton("two")
Dim d As multiton = multiton("zero")
' Dim e As multiton = multiton() ' crashes
' Dim f As multiton = multiton("three") ' crashes
Dim e As multiton = multiton("one")
Dim f As multiton = multiton("two")
Print a.id
Print b.id
Print c.id
Print d.id
Print e.id
Print f.id
Sleep
- Output:
zero_329 one_328 two_531 zero_329 one_328 two_531
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
public final class MultitonTask {
public static void main(String[] args) {
Multiton alpha = Multiton.getInstance(MultitonType.ZERO);
Multiton beta = Multiton.getInstance(MultitonType.ZERO);
Multiton gamma = Multiton.getInstance(MultitonType.ONE);
Multiton delta = Multiton.getInstance(MultitonType.TWO);
System.out.println(alpha);
System.out.println(beta);
System.out.println(gamma);
System.out.println(delta);
}
private enum MultitonType { ZERO, ONE, TWO }
private static final class Multiton {
// Thread safe method.
// Even if the enum 'MultitonType' is maliciously altered to include extra or different enum values,
// for example, 'THREE', the method will return null because the hash map does not contain the enum value.
public static synchronized Multiton getInstance(MultitonType type) {
return instances.getOrDefault(type, null);
}
@Override
public String toString() {
return "This is Multiton " + type;
}
// Private constructor to prevent the class being instantiated
private Multiton(MultitonType aType) {
type = aType;
}
private MultitonType type;
// Thread safe hash map
private static Map<MultitonType, Multiton> instances = new ConcurrentHashMap<MultitonType, Multiton>();
// Create and pre-load into the map all available instances
static {
instances.put(MultitonType.ZERO, new Multiton(MultitonType.ZERO));
instances.put(MultitonType.ONE, new Multiton(MultitonType.ONE));
instances.put(MultitonType.TWO, new Multiton(MultitonType.TWO));
}
}
}
- Output:
This is Multiton ZERO This is Multiton ZERO This is Multiton ONE This is Multiton TWO
A registry (just in memory, not on disk) is used below instead of an enum. The registry is protected by a lock on the Multiton constructor, to prevent two threads creating the same object at the same time.
struct Multiton{T}
data::T
function Multiton(registry, refnum, data)
lock(registry.spinlock)
if 0 < refnum <= registry.max_instances && registry.instances[refnum] isa Nothing
multiton = new{typeof(data)}(data)
registry.instances[refnum] = multiton
unlock(registry.spinlock)
return multiton
else
unlock(registry.spinlock)
error("Cannot create instance with instance reference number $refnum")
end
end
function Multiton(registry, refnum)
if 0 < refnum <= registry.max_instances && registry.instances[refnum] isa Multiton
return registry.instances[refnum]
else
error("Cannot find a Multiton in registry with instance reference number $refnum")
end
end
end
struct Registry
spinlock::Threads.SpinLock
max_instances::Int
instances::Vector{Union{Nothing, Multiton}}
Registry(maxnum) = new(Threads.SpinLock(), maxnum, fill(nothing, maxnum))
end
reg = Registry(3)
m0 = Multiton(reg, 1, "zero")
m1 = Multiton(reg, 2, 1.0)
m2 = Multiton(reg, 3, [2])
m3 = Multiton(reg, 1)
m4 = Multiton(reg, 2)
for m in [m0, m1, m2, m3, m4]
println("Multiton is $m")
end
# produce error
# m3 = Multiton(reg, 4, "three")
# produce error
m5 = Multiton(reg, 5)
- Output:
Multiton is Multiton{String}("zero")
Multiton is Multiton{Float64}(1.0)
Multiton is Multiton{Vector{Int64}}([2])
Multiton is Multiton{String}("zero")
Multiton is Multiton{Float64}(1.0)
ERROR: LoadError: Cannot find a Multiton in registry with instance reference number 5
# 20211215 Perl programming solution
use strict;
use warnings;
BEGIN {
package MultitonDemo ;
use Moo;
with 'Role::Multiton';
has [qw(attribute)] => ( is => 'rw');
$INC{"MultitonDemo.pm"} = 1;
}
use MultitonDemo;
print "We create several instances and compare them to see if multiton is in effect.\n";
print "\n";
print "Instance Constructor Attribute\n";
print "\n";
print "0 multiton 0\n";
print "1 multiton 1\n";
print "2 multiton 0\n";
print "3 new 0\n";
print "4 new 0\n";
my $inst0 = MultitonDemo->multiton (attribute => 0);
my $inst1 = MultitonDemo->multiton (attribute => 1);
my $inst2 = MultitonDemo->multiton (attribute => 0);
my $inst3 = MultitonDemo->new (attribute => 0);
my $inst4 = MultitonDemo->new (attribute => 0);
print "\n";
if ($inst0 eq $inst1) { print "Instance0 and Instance1 share the same object\n" };
if ($inst1 eq $inst2) { print "Instance1 and Instance2 share the same object\n" };
if ($inst0 eq $inst2) { print "Instance0 and Instance2 share the same object\n" };
if ($inst0 eq $inst3) { print "Instance0 and Instance3 share the same object\n" };
if ($inst3 eq $inst4) { print "Instance3 and Instance4 share the same object\n" };
- Output:
We create several instances and compare them to see if multiton is in effect. Instance Constructor Attribute 0 multiton 0 1 multiton 1 2 multiton 0 3 new 0 4 new 0 Instance0 and Instance2 share the same object
No attempt is made for thread safety, since multiple threads accessing these would need
their own locking anyway, not that it is difficult to invoke enter_cs() and leave_cs().
I thought about adding a get_multiton() function to avoid calling new() all the time, but it would (probably/almost certainly) just invoke new() itself anyway.
Put this (up to "end class") in a separate file, to keep allowed and instances private. Classes are not [yet] supported under pwa/p2js.
Technically I suppose this should really use new_dict()/getd()/setd(), but I'm quite sure you'll cope somehow..
without javascript_semantics sequence allowed = {"zero","one","two"}, instances = {NULL,NULL,NULL} public class Multiton public string id function Multiton(string id) integer k = find(id,allowed) if k=0 then crash("not allowed") end if if instances[k] = NULL then this.id = id&sprintf("_%d",rand(999)) instances[k] = this end if return instances[k] end function end class Multiton a = new({"zero"}), b = new({"one"}), c = new({"two"}), d = new({"zero"}), -- e = new(), -- crashes -- f = new({"three"}) -- crashes e = new({"one"}), f = new({"two"}) ?a.id ?b.id ?c.id ?d.id ?e.id ?f.id
- Output:
"zero_651" "one_111" "two_544" "zero_651" "one_111" "two_544"
Although Pluto supports classes (in reality just fancy tables) and static methods, creating a multiton (or singleton) in the language is awkward because the 'private' modifier is ignored when applied to constructors or other static members. Any attempt to return anything other than the instance being created from the constructor is also ignored.
One way around these difficulties is to:
1. Store the instances map in a local variable and then place the multiton class in its own module so the instances map cannot be accessed directly.
2. Throw an error if someone attempts to create another instance of a pre-existing multiton for a given key by calling the constructor directly.
This approach is used in the following example.
The map keys can be any numbers or strings and cannot be changed by the user, though a method is provided to list the available keys. We use an ordered set to store them.
Thread safely is not normally a problem with Pluto as coroutines use cooperative rather than preemptive multithreading and so only one coroutine can run at a time.
-- Multiton.pluto --
require "map"
local mkeys = set.of(0, 1, 2)
local instances = {}
class multiton
static function getInstance(key)
if !instances[key] then new multiton(key) end
return instances[key]
end
static function getKeys() return mkeys:keys():clone() end
function __construct(private key)
assert(mkeys:contains(key), "Argument is not a valid key.")
assert(!instances[key], $"The multiton instance for key {key} already exists.")
instances[key] = self
end
function print()
print($"Hello, I'm a multiton for key {self.key}.")
end
end
-- Multiton_user.pluto --
require "Multiton"
print($"Available keys are: {multiton.getKeys():concat(" ")}")
local s = multiton.getInstance(0)
s:print()
local t = multiton.getInstance(0)
t:print()
print(s == t) -- true, same instance
local u = multiton.getInstance(1)
u:print()
print(s == u) -- false, different instances
print(instances) -- nil
local v = new multiton(3) -- throws an error
v:print() -- not executed
- Output:
$ pluto Multiton_user.pluto Available keys are: 0 1 2 Hello, I'm a multiton for key 0. Hello, I'm a multiton for key 0. true Hello, I'm a multiton for key 1. false nil pluto: ./Multiton.pluto:18: Argument is not a valid key. stack traceback: [C]: in function 'assert' ./Multiton.pluto:18: in field '__construct' [Pluto-injected code]: in local 'Pluto_operator_new' Multiton_user.pluto:15: in main chunk [C]: in ?
#!/usr/bin/python
import threading
class Multiton:
def __init__(self, registry, refnum, data=None):
with registry.lock:
if 0 < refnum <= registry.max_instances and registry.instances[refnum] is None:
self.data = data
registry.instances[refnum] = self
elif data is None and 0 < refnum <= registry.max_instances and isinstance(registry.instances[refnum], Multiton):
self.data = registry.instances[refnum].data
else:
raise Exception("Cannot create or find instance with instance reference number {}".format(refnum))
class Registry:
def __init__(self, maxnum):
self.lock = threading.Lock()
self.max_instances = maxnum
self.instances = [None] * maxnum
reg = Registry(3)
m0 = Multiton(reg, 1, "zero")
m1 = Multiton(reg, 2, 1.0)
m2 = Multiton(reg, 1)
m3 = Multiton(reg, 2)
for m in [m0, m1, m2, m3]:
print("Multiton is {}".format(m.data))
# produce error
#m2 = Multiton(reg, 3, [2])
# produce error
# m3 = Multiton(reg, 4, "three")
# produce error
# m5 = Multiton(reg, 5)
Tried to translate the C# example at WP but not sure if my interpretation/implementation is correct
# 20211001 Raku programming solution
enum MultitonType < Gold Silver Bronze >;
class Multiton {
my %instances = MultitonType.keys Z=> $ ⚛= 1 xx * ;
has $.type is rw;
method TWEAK { $.type = 'Nothing' unless cas(%instances{$.type}, 1, 0) }
}
race for ^10 -> $i {
Thread.start(
sub {
# sleep roll(^2);
my $obj = Multiton.new: type => MultitonType.roll;
say "Thread ", $i, " has got ", $obj.type;
}
);
}
- Output:
Thread 5 has got Bronze Thread 9 has got Gold Thread 7 has got Nothing Thread 8 has got Nothing Thread 3 has got Nothing Thread 2 has got Nothing Thread 1 has got Nothing Thread 0 has got Silver Thread 4 has got Nothing Thread 6 has got Nothing
Rebol [
title: "Rosetta code: Multiton"
file: %Multiton.r3
url: https://rosettacode.org/wiki/Multiton
]
;; Define the valid multiton types
multiton-types: [ZERO ONE TWO]
;; Create the instances map and pre-load all available instances
multiton-instances: make map! []
;; Object factory to create a multiton with a given type
make-multiton: func [aType [word!]] [
make object! [
type: aType
to-string: func [] [
rejoin ["This is Multiton " type]
]
]
]
;; Pre-load instances for all valid types (analogous to Java's static initializer block)
foreach t multiton-types [
multiton-instances/:t: make-multiton t
]
;; getInstance equivalent - returns the instance or none if type is not valid
get-instance: func [type [word!]] [
select multiton-instances type
]
; --- Main ---
alpha: get-instance 'ZERO
beta: get-instance 'ZERO
gamma: get-instance 'ONE
delta: get-instance 'TWO
print alpha/to-string
print beta/to-string
print gamma/to-string
print delta/to-string
- Output:
This is Multiton ZERO This is Multiton ZERO This is Multiton ONE This is Multiton TWO
use std::collections::HashMap;
use std::sync::{Arc, Mutex, OnceLock};
use std::fmt;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
enum MultitonType {
Zero,
One,
Two,
}
#[derive(Debug)]
struct Multiton {
multiton_type: MultitonType,
}
impl Multiton {
// Private constructor
fn new(multiton_type: MultitonType) -> Self {
Self { multiton_type }
}
// Thread-safe method to get instance
// Returns None if the type is not found in the map
pub fn get_instance(multiton_type: MultitonType) -> Option<Arc<Multiton>> {
static INSTANCES: OnceLock<Mutex<HashMap<MultitonType, Arc<Multiton>>>> = OnceLock::new();
let instances = INSTANCES.get_or_init(|| {
let mut map = HashMap::new();
map.insert(MultitonType::Zero, Arc::new(Multiton::new(MultitonType::Zero)));
map.insert(MultitonType::One, Arc::new(Multiton::new(MultitonType::One)));
map.insert(MultitonType::Two, Arc::new(Multiton::new(MultitonType::Two)));
Mutex::new(map)
});
let instances_guard = instances.lock().unwrap();
instances_guard.get(&multiton_type).cloned()
}
// Override toString equivalent
pub fn to_string(&self) -> String {
let type_str = match self.multiton_type {
MultitonType::Zero => "ZERO",
MultitonType::One => "ONE",
MultitonType::Two => "TWO",
};
format!("This is Multiton {}", type_str)
}
}
// Implement Display trait for easy printing (equivalent to << operator overload)
impl fmt::Display for Multiton {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.to_string())
}
}
fn main() {
let alpha = Multiton::get_instance(MultitonType::Zero);
let beta = Multiton::get_instance(MultitonType::Zero);
let gamma = Multiton::get_instance(MultitonType::One);
let delta = Multiton::get_instance(MultitonType::Two);
if let Some(ref a) = alpha {
println!("{}", a);
}
if let Some(ref b) = beta {
println!("{}", b);
}
if let Some(ref g) = gamma {
println!("{}", g);
}
if let Some(ref d) = delta {
println!("{}", d);
}
// Verify that alpha and beta point to the same instance
match (alpha, beta) {
(Some(a), Some(b)) => {
println!("alpha == beta: {}", Arc::ptr_eq(&a, &b));
}
_ => println!("One or both instances are None"),
}
}
- Output:
This is Multiton ZERO This is Multiton ZERO This is Multiton ONE This is Multiton TWO alpha == beta: true
This more or less follows the lines of the C# example in the linked Wikipedia article.
Although all Wren code runs within the context of a fiber (of which there can be thousands) only one fiber can run at a time and so the language is effectively single threaded. Thread-safety is therefore never an issue.
import "./dynamic" for Enum
var MultitonType = Enum.create("MultitonType", ["zero", "one", "two"])
class Multiton {
// private constructor
construct new_(type) {
_type = type
}
static getInstance(type) {
if (!(0...MultitonType.members.count).contains(type)) {
Fiber.abort("Invalid MultitonType member.")
}
if (!__instances) __instances = {}
if (!__instances.containsKey(type)) __instances[type] = new_(type)
return __instances[type]
}
type { _type }
toString { MultitonType.members[_type] }
}
var m0 = Multiton.getInstance(MultitonType.zero)
var m1 = Multiton.getInstance(MultitonType.one)
var m2 = Multiton.getInstance(MultitonType.two)
System.print(m0)
System.print(m1)
System.print(m2)
var m3 = Multiton.getInstance(3) // produces an error
- Output:
zero one two Invalid MultitonType member. [./multiton line 13] in getInstance(_) [./multiton line 33] in (script)