How to Create a Multi-Type List in Mojo?

Hi all! I'm working with Mojo and need to create a list with elements of different data types (integers, strings, booleans, etc.). How can I achieve this? Are there specific collection types or methods in Mojo for mixed data types? Any guidance or documentation links would be greatly appreciated. Thanks in advance!
17 Replies
Aziz
Aziz6mo ago
You can try Tuple: ‘ def main(): var c = Tuple[Int, StringLiteral, Float64](1,"x", 2.2) print(c.get1,StringLiteral) ‘
benny
benny6mo ago
you could also try variant fn main(): alias ListType = Variant[UInt8, Float64, StringLiteral] var list = List[Type](6, 3.14, “b”) you may need to explicitly convert to the variant type, and will need to import from utils.variant
Aziz
Aziz6mo ago
This code raises an error!
No description
Aziz
Aziz6mo ago
It doesn’t not compile with the mojo Playground: https://docs.modular.com/mojo/playground
gryznar
gryznar6mo ago
@benny For me it throws an error:
/__w/modular/modular/Kernels/mojo/stdlib/builtin/_startup.mojo:132:4: error: no viable expansions found
/__w/modular/modular/Kernels/mojo/stdlib/builtin/_startup.mojo:132:4: note: call expansion failed - no concrete specializations
/__w/modular/modular/Kernels/mojo/stdlib/builtin/_startup.mojo:63:4: note: no viable expansions found
/__w/modular/modular/Kernels/mojo/stdlib/builtin/_startup.mojo:78:14: note: call expansion failed - no concrete specializations
/source/prog.mojo:7:4: note: no viable expansions found
fn main():
^
/source/prog.mojo:9:31: note: call expansion failed - no concrete specializations
var list = List[ListType](6, 3.14, "b")
^
/__w/modular/modular/Kernels/mojo/stdlib/utils/variant.mojo:174:8: note: no viable expansions found
/__w/modular/modular/Kernels/mojo/stdlib/utils/variant.mojo:186:25: note: call expansion failed - no concrete specializations
/__w/modular/modular/Kernels/mojo/stdlib/utils/variant.mojo:150:8: note: no viable expansions found
/__w/modular/modular/Kernels/mojo/stdlib/utils/variant.mojo:153:10: note: constraint failed: not a union element type
mojo: error: failed to run the pass manager
/__w/modular/modular/Kernels/mojo/stdlib/builtin/_startup.mojo:132:4: error: no viable expansions found
/__w/modular/modular/Kernels/mojo/stdlib/builtin/_startup.mojo:132:4: note: call expansion failed - no concrete specializations
/__w/modular/modular/Kernels/mojo/stdlib/builtin/_startup.mojo:63:4: note: no viable expansions found
/__w/modular/modular/Kernels/mojo/stdlib/builtin/_startup.mojo:78:14: note: call expansion failed - no concrete specializations
/source/prog.mojo:7:4: note: no viable expansions found
fn main():
^
/source/prog.mojo:9:31: note: call expansion failed - no concrete specializations
var list = List[ListType](6, 3.14, "b")
^
/__w/modular/modular/Kernels/mojo/stdlib/utils/variant.mojo:174:8: note: no viable expansions found
/__w/modular/modular/Kernels/mojo/stdlib/utils/variant.mojo:186:25: note: call expansion failed - no concrete specializations
/__w/modular/modular/Kernels/mojo/stdlib/utils/variant.mojo:150:8: note: no viable expansions found
/__w/modular/modular/Kernels/mojo/stdlib/utils/variant.mojo:153:10: note: constraint failed: not a union element type
mojo: error: failed to run the pass manager
sora
sora6mo ago
It doesn't work for 1 is converted to Int and not UInt8 implicitly. Try this:
from utils import Variant

fn main():
alias ListType = Variant[UInt8, Float64, StringLiteral]
var l = List[ListType](UInt8(1), 1.1, "x")
from utils import Variant

fn main():
alias ListType = Variant[UInt8, Float64, StringLiteral]
var l = List[ListType](UInt8(1), 1.1, "x")
benny
benny6mo ago
thanks for the fix sora, typed it on mobile :p
Arvin_David
Arvin_David6mo ago
Thanks but it seems it's not printable. I tried to print l, even doing a for loop on it and printing the for variable but none of them worked. Somewhere in the output errors, compiler says: failed to infer parameter 'T', argument type 'Reference[Variant[SIMD[ui8, 1], SIMD[f64, 1], StringLiteral], 1, l]' does not conform to trait 'Stringable'
benny
benny6mo ago
You have to dereference to print the value List.iter() returns a Reference to each element, to extract the actual element, you must use the [] syntax, for example
var list = List[Int](1, 2, 3)
for item in list:
print(item[])
var list = List[Int](1, 2, 3)
for item in list:
print(item[])
Arvin_David
Arvin_David6mo ago
Yes, I'm aware of dereferencing but it does not seem to work if the defined List has a variant type as the latest code Sora shared.
benny
benny6mo ago
you you tried item[].get[Stringable]()
sora
sora6mo ago
The code that works will look horrible:
from utils import Variant

fn main():
alias ListType = Variant[UInt8, Float64, StringLiteral]
var l = List[ListType](UInt8(1), 1.1, "x")
for v in l:
var x = v[]
if x.isa[UInt8]():
print(x.get[UInt8]()[])
elif x.isa[Float64]():
print(x.get[Float64]()[])
elif x.isa[StringLiteral]():
print(x.get[StringLiteral]()[])
from utils import Variant

fn main():
alias ListType = Variant[UInt8, Float64, StringLiteral]
var l = List[ListType](UInt8(1), 1.1, "x")
for v in l:
var x = v[]
if x.isa[UInt8]():
print(x.get[UInt8]()[])
elif x.isa[Float64]():
print(x.get[Float64]()[])
elif x.isa[StringLiteral]():
print(x.get[StringLiteral]()[])
You could also use x.take[...]() to save a deref
Arvin_David
Arvin_David6mo ago
OMG, That's terrible! I don't know what the get method does and also cannot understand why in a single type list, just a dereferencing works, but here, we need such a tweak. Do you think it's going to be fixed? Because I deeply believe that Mojo's collections are not well documented with examples or explanations and very very hard to work with. Modular wants developers to bring their ideas into Mojo but it's using Python's syntax while not keeping its beauty even after being open-sourced. I understand it's going to take a while but powerful easy-to-use datatypes are on top of priorities even before the Windows version release. Because I think we need a community-acceptable language before making it public for use. I mean it's still truly usable but not user-friendly at all in many cases… However curious to know more about its future. I appreciate knowing others' ideas. P.S. Modular wants to bring a lovely language with a full dynamism basis (Python) to the language compilers world. That's wonderful and time-consuming, but are we even slowly getting there? I believe current clues about not resolved limitations show something else.
sora
sora6mo ago
There is a certain price you need to pay for performance. Heterogeneous list is a difficult thing to optimise. Mojo might have one one day, but a better version of what we have here is also invaluable. With enum on the road map, we can expect something like the following in the future (with place holder syntax):
enum ListType:
case UInt8
case Float64
case StringLiteral

fn __str__(self) -> String:
match self:
case UInt8(n): return str(n)
...
...

fn main():
var l: List[ListType] = [UInt8(1), 1.1, "x"]
for v in l:
print(v[])
enum ListType:
case UInt8
case Float64
case StringLiteral

fn __str__(self) -> String:
match self:
case UInt8(n): return str(n)
...
...

fn main():
var l: List[ListType] = [UInt8(1), 1.1, "x"]
for v in l:
print(v[])
If you are more dynamic leaning, something like the following may also work in the future:
fn main():
var l: List[Stringable] = [UInt8(1), 1.1, "x"]
for v in l:
print(v[])
fn main():
var l: List[Stringable] = [UInt8(1), 1.1, "x"]
for v in l:
print(v[])
But there is a price you have to pay for performance and type safety.. If you look at Swift, it's perfectly dynamically capable, and it's a statically typed language at core. So there is reason to believe that Mojo is only going to do better. It's a bit off topic, but people have different backgrounds and would want different things from Mojo the language. I personally think "just another python" doesn't solve the problem Mojo is set out to solve: heterogeneous computing, unify Ai infrastructure etc. So, if you want to use Mojo for your daily Python use if you are not in the Ai niche, it's not going to happen for a long time.
Arvin_David
Arvin_David6mo ago
I completely understand but things differ when people track mojo because of the revolutionary movements they state they can build. So then being Python's superset promise is a fake marketing statement when we are not going to have the available dynamism in Python right? I remember in one of the streams that Modular had, they said that they really look forward to running Python packages natively in Mojo but they are far from there at that moment. So this sight is not more than a dream when simple or complicated packages rely on this dynamism like pandas. When we can't parse them, we can't run them in now or the future, right? It personally seems like a huge conflict between desires, modular dreams, their statements, and the reality we are facing as you also explained. I could say these to Rust core developers but it certainly matters what we expect from who. That's where the brand, the team, and their previous statements become considerable. Nevertheless, I appreciate any revolutionary movement forward for narrowing down the gap between dreams and realities.
Want results from more Discord servers?
Add your server