Enumerator based coroutine yielding
Hey! One of the features that's missing from moonsharp that'd make writing lua code a lot more elegant would be support for yielding a coroutine in clr functions In unity this is usually done by just having an enumerator/generator function (not sure of the 100% correct terminology):
IEnumerator MyCoroutine(int counter) {
for (int i = 0: i < counter; i++) {
yield return i;
}
}
You can do something like this already, but you'll have to manually keep track of the iterator:
for i in my_coroutine(10) do
coroutine.yield(i)
end
Conceptually it shouldn't be too hard to just add some "syntactical sugar" to implement something similar to the lua function above behind the scenes.. So I decided to give that a try and went digging First I looked at the custom converters and figured it'd be as easy as checking for an attribute on the method info and just giving it a different DynValue with the "for loop yield" part, but turns out classes don't even use that and I had to go a lot deeper
[MoonSharpClrCoroutine]
IEnumerator YieldExample(int counter) {
for (int i = 0: i < counter; i++) {
yield return i;
}
}
This is obviously a giant hack at the moment and I'm mainly looking for feedback to get this to a decent state where merging it might be considered The whole MethodMemberDescriptor part can be implemented better, but I didn't want to dig too deep into the scary parts for a proof of concept I'm also curious what the best way would be to generate the iterator wrapper part? From what I gathered the yield does need to be run in bytecode currently
Oh, usecase
The usecase for this would be nicer yielding in api functions while we wait for things to happen/be ready A dialogue system is probably an easy example
dialogue:say("Hello please give me your name")
local name = dialogue:input()
dialogue:clear()
dialogue:say("Hi ".. name)
Currently dialogue:input() would be implemented with lua wrapper function calling coroutine.yield until we have an input response, but obviously this pretty much means you have to implement every api twice - once in c# for the actual api and once as a lua wrapper for yielding
Yeah, in a final version you'd want to get rid of the lua code parsing and clean up the code all together This is just a proof of concept, it also has issues of not yielding null values, since those aren't valid in lua "iterators"
I wouldn't recommend using this as is
On 2 Sep 2020, at 22:04, Chris Smoak [email protected] wrote:
@cesmoak commented on this pull request.
In src/MoonSharp.Interpreter/Interop/StandardDescriptors/ReflectionMemberDescriptors/MethodMemberDescriptorCoroutine.cs:
var enumerateYielder = script.DoString(@"return function (callable)
- return function (...)
for y in callable(...) doif coroutine.is_return_value(y) thenreturn coroutine.get_return_value(y)elsecoroutine.yield(y)endend- end +end", null, MethodInfo + "_yielder"); Does it make sense to parse this lua code one for performance reasons? Could this lua function be pulled out and kept as a global function to be used when needed? I've done something similar in my own code, though all on the lua side without the C# interconnection work this PR does to make it nice and clean.
— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub, or unsubscribe.