M
Modular10mo ago
benny

partially unbound parameters as return values?

struct Person[Age: UInt8, coder: Bool]:
...

fn example(p: Person) -> Person[p.Age, *_]:
...
struct Person[Age: UInt8, coder: Bool]:
...

fn example(p: Person) -> Person[p.Age, *_]:
...
This code will not compile and instead gives 'Person' missing required parameter 'coder'mojo. Is this intended behavior? I can see how given lambda functions one could represent every possible relationship between compile time constants in a function, but this seems a little excessive, especially once we get into nested parametric types, any ideas?
10 Replies
ModularBot
ModularBot10mo ago
Congrats @benny, you just advanced to level 7!
benny
bennyOP10mo ago
The obvious solution is making 'coder' not required by giving it a default value, but for Boolean expressions, this leads to if statement with constant condition 'if True'mojo whenever evaluating relative to this, meaning the compiler is not asuming the value is ?, it is assuming it is the default unless otherwise provided
sora
sora10mo ago
Person[coder=True] is a different type from Person[coder=False], I think what you want is actually a existential?
benny
bennyOP10mo ago
can you give an example of that?
sora
sora10mo ago
I meant the semantics you want is kinda not supported right now. You either return a Variant or a existential which we don't have. If you think about it, we also cannot return a SIMD with variable length. Or to put it another way, what is your intended semantics?
benny
bennyOP10mo ago
could you do some meta programming for that? like with the simd example, could you make a function that takes compile time variables and calculates the length that will be returned of a function, then return a simd of that return values length? I can’t see why not, it’s the same as returning p.Age * 2
sora
sora10mo ago
You can, but that would be different from having a "unbounded" parameter. It's different because otherwise the compiler needs to look into the function body to type check it. You could do this instead:
struct Person[Age: UInt8, coder: Bool]:
...

fn foo(coder: Bool) -> Bool:
...

fn example(p: Person) -> Person[p.Age, foo(p.coder)]:
...
struct Person[Age: UInt8, coder: Bool]:
...

fn foo(coder: Bool) -> Bool:
...

fn example(p: Person) -> Person[p.Age, foo(p.coder)]:
...
benny
bennyOP10mo ago
yes that’s what i mean i’ll give it a shot, thanks sora
sora
sora10mo ago
The ergonomics probably won't be as good as you'd like it to be. ref So you may need to use rebind, and in turn the Person struct needs to be AnyRegType.
@value
@register_passable
struct Person[Age: UInt8, coder: Bool]:
...

@always_inline
fn foo(coder: Bool) -> Bool:
return coder

fn example(p: Person) -> Person[p.Age, foo(p.coder)]:
return rebind[Person[p.Age, foo(p.coder)]](p)
@value
@register_passable
struct Person[Age: UInt8, coder: Bool]:
...

@always_inline
fn foo(coder: Bool) -> Bool:
return coder

fn example(p: Person) -> Person[p.Age, foo(p.coder)]:
return rebind[Person[p.Age, foo(p.coder)]](p)
GitHub
[BUG]: Behaviour of the type checker is inconsistent (some expressi...
Bug description I've recently been trying to understand how the type checker reasons about the equality of types. I've noticed a few inconsistencies and potential bugs. These are demonstrat...
benny
bennyOP10mo ago
@sora would you be willing to give some code a look? Still not able to fix the issue my new problem is storing and retreiving partially unbound structs and having the structs be stored still does that make sense? assuming a vector impl, I can store
Vector[Node[T, *_]]
Vector[Node[T, *_]]
, the problem is after loading and using those values, or using that value as the input to a function nvm, got it with some clever rebinds :) thanks sora
Want results from more Discord servers?
Add your server