Is this broken or is it me? Parameterized function alias...

alias ExampleFn = fn [L: Int] (Int32) -> SIMD[DType.uint8, L];

fn example_fn_1 [L: Int] (default: Int32) -> SIMD[DType.uint8, L]:
return SIMD[DType.uint8, L](default);


struct ExampleStruct:
var example_fn: ExampleFn;

fn __init__(inout self):
self.example_fn = example_fn_1;

""" This works fine """
fn make_buffer_ok [L: Int] (inout self, default: Int32) -> SIMD[DType.uint8, L]:
return example_fn_1[L](default);

""" This does not work """
fn make_buffer_sad [L: Int] (inout self, default: Int32) -> SIMD[DType.uint8, L]:
return self.example_fn[L](default);
alias ExampleFn = fn [L: Int] (Int32) -> SIMD[DType.uint8, L];

fn example_fn_1 [L: Int] (default: Int32) -> SIMD[DType.uint8, L]:
return SIMD[DType.uint8, L](default);


struct ExampleStruct:
var example_fn: ExampleFn;

fn __init__(inout self):
self.example_fn = example_fn_1;

""" This works fine """
fn make_buffer_ok [L: Int] (inout self, default: Int32) -> SIMD[DType.uint8, L]:
return example_fn_1[L](default);

""" This does not work """
fn make_buffer_sad [L: Int] (inout self, default: Int32) -> SIMD[DType.uint8, L]:
return self.example_fn[L](default);
The error is:
/home/pi/Development/mojo-lgpio/test.mojo:20:31: error: 'fn[Int](SIMD[int32, 1]) -> SIMD[uint8, $0]' is not subscriptable, it does not implement the `__getitem__`/`__setitem__` or `__refitem__` methods
return self.example_fn[L](default);
/home/pi/Development/mojo-lgpio/test.mojo:20:31: error: 'fn[Int](SIMD[int32, 1]) -> SIMD[uint8, $0]' is not subscriptable, it does not implement the `__getitem__`/`__setitem__` or `__refitem__` methods
return self.example_fn[L](default);
Basically, I need to use pattern of make_buffer_sad because I am using FFI to write a wrapper around lgpio...
8 Replies
ModularBot
ModularBot2mo ago
Congrats @xentropy, you just advanced to level 2!
xentropy
xentropy2mo ago
I guess there are limitations with Python and reading SPI bus for some high speed ADCs, so I thought this is a great use case for Mojo. I got around it by using DTypePointer but still wondering if this should have worked.
Ryulord
Ryulord2mo ago
This works:
fn example_fn_1[X: Int](default: Int32) -> SIMD[DType.uint8, X]:
return SIMD[DType.uint8, X](default.cast[DType.uint8]())


struct ExampleStruct[L: Int]:
var example_fn: fn(Int32) -> SIMD[DType.uint8, L]

fn __init__(inout self):
self.example_fn = example_fn_1[L]

fn make_buffer_ok(inout self, default: Int32) -> SIMD[DType.uint8, L]:
return example_fn_1[L](default)

fn make_buffer_sad(inout self, default: Int32) -> SIMD[DType.uint8, L]:
return self.example_fn(default)
fn example_fn_1[X: Int](default: Int32) -> SIMD[DType.uint8, X]:
return SIMD[DType.uint8, X](default.cast[DType.uint8]())


struct ExampleStruct[L: Int]:
var example_fn: fn(Int32) -> SIMD[DType.uint8, L]

fn __init__(inout self):
self.example_fn = example_fn_1[L]

fn make_buffer_ok(inout self, default: Int32) -> SIMD[DType.uint8, L]:
return example_fn_1[L](default)

fn make_buffer_sad(inout self, default: Int32) -> SIMD[DType.uint8, L]:
return self.example_fn(default)
There were a couple problems. 1. It looks like like you can't parameterize a parametric function pointer type in an alias. Not sure why though. 2. Your struct needed to be parameterized at the struct level so it knows that the different parts are parameterized in the same way. also you forgot to cast from Int32 to UInt8
xentropy
xentropy2mo ago
Thanks! I was trying to avoid parameterizing the struct itself. I am reading a different number of bytes every time, but the number of bytes is known at compile time. I don't want to create a new struct everytime I read the bytes. It seems like you should able to parameterize just the function, no?
Ryulord
Ryulord2mo ago
You can parametrize just a function but having a method and a field on a struct both parameterized in the same way requires you to parameterize the struct. It's not clear to me why you need the struct without knowing more about the use case but you might be better off with just a function
xentropy
xentropy2mo ago
just trying to do something object oriented, but you're right. there's a file handle that persists between function calls, so I thought I'd store the handle in the same struct as the group of functions that will use it. if I were willing to throw that away I could just use functions at the module level and I think the issue would be solved.
fn example_fn_1 [L: Int] (handle: Int32, default: UInt8) -> SIMD[DType.uint8, L]:
return SIMD[DType.uint8, L](default);


var example_fn_2: fn [L: Int] (Int32, UInt8) -> SIMD[DType.uint8, L] = example_fn_1;

fn main():
"""doesn't work."""
example_fn_2[15](0, 1)


"""works."""
example_fn_1[15](0, 1)
fn example_fn_1 [L: Int] (handle: Int32, default: UInt8) -> SIMD[DType.uint8, L]:
return SIMD[DType.uint8, L](default);


var example_fn_2: fn [L: Int] (Int32, UInt8) -> SIMD[DType.uint8, L] = example_fn_1;

fn main():
"""doesn't work."""
example_fn_2[15](0, 1)


"""works."""
example_fn_1[15](0, 1)
I don't know. This kind of feels like an issue with function pointers.
Ryulord
Ryulord2mo ago
You can't parameterize a runtime value. Parameterization means the compiler actually makes a specialized version of the thing and so it needs to happen at compile time.
xentropy
xentropy2mo ago
gotcha. so what I'm trying to do is fundamentally incorrect.
Want results from more Discord servers?
Add your server