Type State Pattern
Does anybody have a code-snippet that demonstrates a standard Type State Pattern in Mojo?
For example, a somewhat textbook-example of a traffic light -- please excuse any typos I make in my sloppy hand-jam example.
Anyway, does anybody have a snippet of Mojo-style Type State Pattern? Google says "no," but I imagine somebody has a personal snippet they might share.
31 Replies
Here's what I was noodling around with ... granted, I'm wrapping the concept in a container-struct:
However, there are two errors:
1.
'Variant' parameter #0 has 'CollectionElement' type, but value has type 'AnyStruct[Red]'
(Mojo LSP marks term Red
in the line alias TrafficLightState...
)
2. dynamic type values not permitted yet
(Mojo LSP marks term Red
in the line self.state = Red
in the init function)
And I know that an easy solution is using placeholder values to represent the state, like ints or strings:
But this pattern does not prevent the mistake of doing something in the code like:
While that error can be prevented by having rigid adherence to defined values, such as Rust Enum values or a Mojo Variant of acceptable types, or something. Just not sure what my "something" is going to be, so I'm looking for some hand-holding. ๐
I should also add that I'm really not doing the Type State Pattern in the Mojo example, but rather a modified "use a placeholder of state
" shortcut. And not thrilled about that.
next flailing attempt is this, which still has the above "error #1"
This is incorrect rust. Your TL should have been a parametric structure with phantom
just add @value to Red, Green, and Yellow
I'm not a heavy-duty Rust dev, but I've seen both structs with phantom and enums for typestate pattern. So, might be a holy war. Dunno.
But beyond any Rust holy wars, what is pattern in Mojo?
will try.. gimme sec
can also drop the empty
__init__
s if you do thatCongrats @Ryulord, you just advanced to level 5!
What do you mean by holy war? I was merely pointing out that your rust code is invalid, not the approach you chose is wrong. They both could work, which one you choose depends on what you want to achieve. If you want to see your state in the type, you will use phantom type. Otherwise, itโs just good old adt.
ok, so then there are a bunch of Rust tutorials, repos, etc that are using Algebraic Data Types as pseudo-typestate. I was misled in terminology by the resources I encountered in my limited Rust exposure.
Moving forward, what would you say is an ideal Type State Pattern in Mojo? How would you achieve something that uses parametric structure with phantom data that allows you to see your state?
I feel like I'm fumbling and just adding random
[]
s and what not to see what new errors I can stumble into. ๐Proper type state not achievable yet I think, because we donโt have conditional conformance.
Wait, actually, there is a horrible hack you can use in todayโs Mojo.
Will get back to you when Iโm on my laptop.
โค๏ธ Horrible hacks are my jam! ๐ And I'm grateful for your willingness to do some hand-holding here.
This seems fine for now: https://discord.com/channels/1087530497313357884/1098713601386233997/1209357999529926696
Since Mojo supports overload (unlike rust), you could write the transition function as a free function. I think you can encode any finite automata this way
I am really thankful for your thoughts. I appreciate all the coaching and guidance. .....I'm pretty sure I'll find a way to mess-it-up when I try to implement, but I'm ok with "learning opportunities" ๐
Jests aside: sincere gratitude. Thank you.
@bunny Now, the horrible hack:
This is different form using enum in that the state info is encoded in the type. It's less convenient than using a free function, since the return type is not inferred. But is does provide the compile time guarantee (with
@parameter if
).@sora , it looks like the result of
next
is wholly controlled by the type passed to it. I.e., the B
in s.next[B]()
. What is to prevent somebody from typo'ing as s.next[A]()
?
I was messing around with what you provided, and realized I could just pass any state change desired. In this example, the traffic light goes from Red to Yellow.
How do I prevent this "dev typo'd and now we have improper proper order of change" error?Hmmmm, that's not what i expected
I think it's a bug in
rebind
, or I got its semantics wrong.
Two hacks you could use for the moment
So here's where I'm at:
Thank you, @sora ! ...I might rethink what I'm making to use a different pattern, because this looks a bit fragile to me. I cannot explain why, just a spidey-sense thing. Perhaps my inner-paranoiac is saying "will this be compatible with Mojo v1.0, or am I setting myself up for a lot of refactoring as features change"..... really don't know.
Serious HUGE thank you for helping me navigate through some of Mojo's features.
@bunny I'd probably stick to this
so more like?
Which results in the pic:
Pretty sure I owe you a coffee or smth. โ
First Mojo-CON, your AM coffee is on me. ๐
Every bit of guidance just makes me explore new junk. ๐
Ok, so I thought "what if I just make each color Stringable"...? But I'm seriously borking up something very basic here and feeling rather sheepish. Any idea what magical ASCII I need in the line
return str(Self.T)
to make things work?
Code:
Errors:
Congrats @bunny, you just advanced to level 4!
fwiw, I've tried a few "magical ASCII" permutations that all are wrong. I'm just not grasping what I need to pass inside the
str()
to make it trigger the Self.T
's __str__()
method.__str__
won't work be because it needs an instance of T
, which is why I opt to make a static method on the state types.ok, I guess I was hoping I could trick the compiler with some slight of hand or something ๐
Thank you for all of this hand-holding. Right now, I'm finding myself really more confused than not with Mojo. But, I've learned a bunch of languages over the years -- maybe not to "mastery" but to Good Enough (tm) and to a level where I could contribute to production code in those languages. I'll get there with Mojo. I think that I just really want to contribute to some foundational stuff too, and that requires me to go quite a bit farther in my understanding.
Thank you, sora.
@bunny @sora
Any thoughts?
Sorry slow to respond. Been busy, busy.
As it is, I get compilation errors. In the
TrafficLight.__init__()
method, I changed it to self.state = Red()
to remove a couple errors. The remaining errors are:
I really need to carve out some time to really explore Mojo's Variants a bit more. I read the docs and made a couple trite little code snippet test Variants, but I need to play a lot more when time permits.Yeah, Iโm confused why itโs saying it isnโt confirming to the type