# How to create a list of trait

**URL:** <https://forum.modular.com/t/how-to-create-a-list-of-trait/1465>\
**Category:** Mojo\
**Created:** [May 17, 2025, 9:36am UTC](https://forum.modular.com/t/how-to-create-a-list-of-trait/1465 "2025-05-17T09:36:21Z")\
**Posts on this page:** 10\
**Page:** 1

<div class="post-metadata">

**Author:** ![aj3423](https://avatars.discourse-cdn.com/v4/letter/a/58f4c7/32.png) [@aj3423](https://forum.modular.com/u/aj3423)\
**Post date:** [May 17, 2025, 9:36am UTC](https://forum.modular.com/t/how-to-create-a-list-of-trait/1465/1 "2025-05-17T09:36:21Z")

</div>

I have a list of operations, e.g.: `Add`, `Sub`, etc… I need to apply them to some numbers.

But I can’t find a way to create a List of trait

```auto
from collections import List

trait Operation(Copyable & Movable):
	pass

fn main():
	var list = List[Operation]() # error

```

It fails with error:

> ```auto
> error: cannot implicitly convert 'AnyTrait[Operation]' value to 'Copyable & Movable' in type parameter
> var list = List[Operation]() # error
> ^ ~~~~~~~~
> 
> ```

Any workaround? Thanks.

---

<div class="post-metadata">

**Author:** ![sora](https://avatars.discourse-cdn.com/v4/letter/s/ad7895/32.png) [@sora](https://forum.modular.com/u/sora)\
**Post date:** [May 17, 2025, 12:27pm UTC](https://forum.modular.com/t/how-to-create-a-list-of-trait/1465/2 "2025-05-17T12:27:31Z")

</div>

Hi! We don’t support existentials yet, so you can’t put trait objects in a list.

That said, this sounds like a case where enums really shine:

```mojo
from utils import Variant

@fieldwise_init # if you are on nightly
struct Add(Copyable, Movable):
  ...

@value # if you are on 25.3
struct Mul:
  ...

alias Op = Variant[Add, Mul]

fn main():
  add = Op(Add())
  mul = Op(Mul())
  l = List[Op](add, mul)

```

---

<div class="post-metadata">

**Author:** ![xtxtxtxtxtx](https://avatars.discourse-cdn.com/v4/letter/x/dec6dc/32.png) [@xtxtxtxtxtx](https://forum.modular.com/u/xtxtxtxtxtx)\
**Post date:** [May 17, 2025, 12:37pm UTC](https://forum.modular.com/t/how-to-create-a-list-of-trait/1465/3 "2025-05-17T12:37:48Z")

</div>

Might wanna remove `@value` from example as it will soon be removed. So other can see in future.

---

<div class="post-metadata">

**Author:** ![aj3423](https://avatars.discourse-cdn.com/v4/letter/a/58f4c7/32.png) [@aj3423](https://forum.modular.com/u/aj3423)\
**Post date:** [May 17, 2025, 2:33pm UTC](https://forum.modular.com/t/how-to-create-a-list-of-trait/1465/4 "2025-05-17T14:33:35Z")

</div>

Thank you very much.

The working code:

```auto
from utils import Variant

@fieldwise_init 
struct Add(Copyable, Movable):
	var a: Int
	var b: Int

	fn __copyinit__ (out self, other: Self):
		self.a = other.a
		self.b = other.b

	fn __moveinit__ (out self, owned other: Self):
		self.a = other.a
		self.b = other.b

	fn calc(self) -> Int:
		return self.a + self.b

@fieldwise_init  
struct Mul(Copyable, Movable):
	var a: Int
	var b: Int

	fn __copyinit__ (out self, other: Self):
		self.a = other.a
		self.b = other.b

	fn __moveinit__ (out self, owned other: Self):
		self.a = other.a
		self.b = other.b

	fn calc(self) -> Int:
		return self.a * self.b

alias Op = Variant[Add, Mul]

fn main():
	add = Op(Add(1,2))
	mul = Op(Mul(3,4))
	l = List[Op](add, mul)

	for op in l: 
		if op[].isa[Add](): # <---- is it supposed to be used like this
			print(op[][Add].calc())
		if op[].isa[Mul]():
			print(op[][Mul].calc())

```

Looking forward to the `List[trait]` support 😀

---

<div class="post-metadata">

**Author:** ![aj3423](https://avatars.discourse-cdn.com/v4/letter/a/58f4c7/32.png) [@aj3423](https://forum.modular.com/u/aj3423)\
**Post date:** [May 18, 2025, 9:07am UTC](https://forum.modular.com/t/how-to-create-a-list-of-trait/1465/5 "2025-05-18T09:07:15Z")

</div>

The code becomes very complex when there’re lots of `.isa[]()`, so I ended up using high order functions:

```auto
alias F = fn(Int) escaping -> Int

fn add(x: Int) -> F:
	fn inner(y: Int) -> Int:
		return x + y
	return inner

fn mul(x: Int) -> F:
	fn inner(y: Int) -> Int:
		return x * y
	return inner

fn main(): 
	var result = 1

	var list = List[F](add(7), mul(11))
	for f in list:
		result = f[](result)
	
	print(result) 

```

---

<div class="post-metadata">

**Author:** ![EzRyder](https://sea1.discourse-cdn.com/flex001/user_avatar/forum.modular.com/ezryder/32/133_2.png) [@EzRyder](https://forum.modular.com/u/EzRyder)\
**Post date:** [May 19, 2025, 12:44am UTC](https://forum.modular.com/t/how-to-create-a-list-of-trait/1465/6 "2025-05-19T00:44:24Z")

</div>

I see you already have a solution, but your initial question triggered my curiosity to find an elegant algorithm. Initially I thought you needed a parallel approach, then later I saw your ‘higher order’ solution which uses sequential calculations, so I worked that out too. In short, the sequential solution below performs the same calculations as in your example (I think). The parallel algorithm does not, but I thought it worth sharing FWIW. Cheers!

```mojo
from algorithm.functional import parallelize

alias fn_sig = fn (a: Int, b: Int) -> Int

struct Op(Copyable & Movable):
    """Contains mathematical operations."""

    alias Add = Self.add
    alias Mul = Self.mul

    var operation: fn_sig
    var a: Int
    var b: Int

    fn __init__ (out self, operation: fn_sig, a: Int, b: Int):
        self.operation = operation
        self.a = a
        self.b = b

    @parameter
    fn __call__ (self, out value: Int):
        """Parallel - returns values from initial arguments."""
        value = self.operation(self.a, self.b)

    @parameter
    fn __call__ (self, mut value: Int):
        """Sequential - mutates the 'value' argument."""
        value = self.operation(value, self.b)

    @staticmethod
    fn bind(func: fn_sig, a: Int, b: Int, out result: Self):
        result = Self(func, a, b)

    @staticmethod
    fn add(a: Int, b: Int, out value: Int):
        value = a + b

    @staticmethod
    fn mul(a: Int, b: Int, out value: Int):
        value = a * b

fn main():
    alias RESIZE_DEFAULT = -1 # Value not important.
    operations = List[Op]()

    # 1) Sequential calculations.
    value = 1
    operations.append(Op.bind(Op.Add, value, 7))
    operations.append(Op.bind(Op.Mul, value, 11))

    # Perform Sequential calculations.
    for op in operations:
        op[](value)
    print("Sequential value =", String(value))
    print()

    # 2) Parallel calculations.
    print("Parallel results:")
    operations.clear()
    operations.append(Op.bind(Op.Add, 1, 2))
    operations.append(Op.bind(Op.Mul, 3, 4))
    operations.append(Op.bind(Op.Add, 5, 6))
    operations.append(Op.bind(Op.Mul, 7, 8))
    operations.append(Op.bind(Op.Add, 9, 10))

    results = List[Int]()
    results.resize(len(operations), RESIZE_DEFAULT)

    # Nested function for parallel calculations.
    @parameter
    fn calc(index: Int):
        results.insert(index, operations[index]())
        print("results[" + String(index) + "] =", results[index])

    # Perform parallel calculations.
    num_work_items = len(operations)
    num_workers = num_work_items
    parallelize[calc](num_work_items, num_workers)

```

**Output:**

```txt
Sequential value = 88

Parallel results:
results[0] = 3
results[4] = 19
results[1] = 12
results[3] = 56
results[2] = 11

```

---

<div class="post-metadata">

**Author:** ![aj3423](https://avatars.discourse-cdn.com/v4/letter/a/58f4c7/32.png) [@aj3423](https://forum.modular.com/u/aj3423)\
**Post date:** [May 19, 2025, 2:47pm UTC](https://forum.modular.com/t/how-to-create-a-list-of-trait/1465/7 "2025-05-19T14:47:33Z")

</div>

@EzRyder Thank you/ sir. I see the point is to wrap the function in a struct, this makes it possible to add some debug information of the function. But I prefer implementng them separately, it’s easier to maintain.  
The updated code:

```auto
alias F = fn(y: Int) escaping -> Int
alias Debug = fn() escaping -> String

@fieldwise_init
struct Wrapper(Movable & Copyable):
	var f: F
	var debug: Debug

	fn __call__ (self, b: Int) -> Int:
		return self.f(b)

fn add(x: Int) -> Wrapper:
	fn f(y: Int) -> Int:
		return x + y

	fn debug() -> String:
		return String("+") + x. __str__ ()

	return Wrapper(f, debug)

fn mul(x: Int) -> Wrapper:
	fn f(y: Int) -> Int:
		return x * y

	fn debug() -> String:
		return String("*") + x. __str__ ()

	return Wrapper(f, debug)

fn main(): 
	var result = 1

	var list = List(add(7), mul(11))
	for f in list:
		print("operation: " + f[].debug())
		result = f[](result)
	
	print(result)

```

Output:

operation: +7  
operation: \*11  
88

---

<div class="post-metadata">

**Author:** ![EzRyder](https://sea1.discourse-cdn.com/flex001/user_avatar/forum.modular.com/ezryder/32/133_2.png) [@EzRyder](https://forum.modular.com/u/EzRyder)\
**Post date:** [May 20, 2025, 4:29pm UTC](https://forum.modular.com/t/how-to-create-a-list-of-trait/1465/8 "2025-05-20T16:29:03Z")

</div>

> [@xtxtxtxtxtx](#):
>
> Might wanna remove `@value` from example as it will soon be removed. So other can see in future.

This isn’t on my radar. What’s the background/timeline for this change?

---

<div class="post-metadata">

**Author:** ![sora](https://avatars.discourse-cdn.com/v4/letter/s/ad7895/32.png) [@sora](https://forum.modular.com/u/sora)\
**Post date:** [May 20, 2025, 4:43pm UTC](https://forum.modular.com/t/how-to-create-a-list-of-trait/1465/9 "2025-05-20T16:43:14Z")

</div>

> <https://github.com/modular/modular/blob/main/mojo/proposals/upgrading-value-decorator.md>

---

<div class="post-metadata">

**Author:** ![Ethan](https://avatars.discourse-cdn.com/v4/letter/e/8dc957/32.png) [@Ethan](https://forum.modular.com/u/Ethan)\
**Post date:** [July 17, 2025, 8:20am UTC](https://forum.modular.com/t/how-to-create-a-list-of-trait/1465/10 "2025-07-17T08:20:13Z")

</div>

Here is an approach using a trait object and dynamic dispatch.

```mojo
from memory import ArcPointer

trait Op(Copyable, Movable):
	fn calc(self) -> Int:
		pass

fn calc_trampoline[T: Op](ptr: ArcPointer[NoneType]) -> Int:
    var data = rebind[ArcPointer[T]](ptr)
    return data[].calc()

fn clear_trampoline[T: Op](var ptr: ArcPointer[NoneType]):
    var data = rebind[ArcPointer[T]](ptr^)
    _ = data^

struct DynOp(Op):
	var data: ArcPointer[NoneType]
	var calc_func: fn(ArcPointer[NoneType]) -> Int
	var clear_func: fn(var ArcPointer[NoneType])
	
	fn __init__ [T: Op](out self, var ptr: ArcPointer[T]):
		self.data = rebind[ArcPointer[NoneType]](ptr^)
		self.calc_func = calc_trampoline[T]
		self.clear_func = clear_trampoline[T]
	
	fn calc(self) -> Int:
		return self.calc_func(self.data)
	
	fn __del__ (var self):
		self.clear_func(self.data^)

@fieldwise_init 
struct Add(Op):
	var a: Int
	var b: Int

	fn calc(self) -> Int:
		return self.a + self.b

@fieldwise_init  
struct Mul(Op):
	var a: Int
	var b: Int

	fn calc(self) -> Int:
		return self.a * self.b

def main():
	var add = ArcPointer(Add(1,2))
	var mul = ArcPointer(Mul(3,4))
	var l: List[DynOp] = [DynOp(add), DynOp(mul)]

	for op in l:
		print(op.calc())

```

Notice that this implementation is open compared to the one using `variant` in the sense that you can add new types that conform to the `Op` trait without changing existing code.
