Message creation treats empty list as failure
I think
task-create-error-on-failure
treats its dependency task as failed if it results in an empty list. Here’s a concrete example:farg-ty := <type-match(|ctx, BuiltInArgTypes())> (ty, name); msg := <task-create-error-on-failure(|ctx, farg-ty, "unknown buit-in function")> name
with a corresponding
task-match
:task-match: (BuiltInArgTypes(), (NodeTy(_), "NumNbrs")) -> []
Given the above the message always shows up. I can confirm that the
task-match
above actually gets called and that thefarg-ty
task executed successfully and produces the empty list. If i change it to:task-match: (BuiltInArgTypes(), (NodeTy(_), "NumNbrs")) -> ["foo"]
Then the message no longer appears.
This makes me to believe that
Submitted by Vlad Vergu on 9 July 2013 at 18:11[ ]
as a task result is treated as task failure. Maybe this is conceptually related to https://yellowgrass.org/issue/NaBL/50.
Issue Log
It treats an empty list as failed, why is that an error?
You can tag this issue as anything, it doesn’t change the fact that empty result set is a valid task result.
Everything in the execution path succeeds but the message task treats it as failed. In the specific example above empty list is perfectly correct and normal corresponding to a function with no arguments.
The message task itself results in an empty list. Should that be interpreted as always failing?
Ok, so the error is that
[]
is used as a succeeding task result but is interpreted as a failure by the message task. Shouldn’t argument types be wrapped in another list btw?
Yes that is the error. I’m not sure what you mean by wrapping the argument types. Suggesting:
task-match: (BuiltInArgTypes(), (NodeTy(_), "NumNbrs")) -> [ [ ] ]
? This seems a bit weird, but might work.
I think these are two issues:
- How
task-match
is called in the Rewrite task. It seems not to put the result into a single result list, because I might not have been aware of the list semantics. But I might have fixed this in my branch already. I think this is the main issue here and should be fixed, that Rewrite returns a list of results. The user-defined rewrite rule should produce a single result, not a list. Thus, it can produce a list as a result, but not a list of results. I think this is also causing the confusion for Vlad.- How to handle list-valued properties consistently, particular in common cases such as argument lists. I was experimenting on that in MiniJava, but did not come to a conclusion yet and probably will not before the end of next week.
@Vlad: Wasn’t that what you were doing with normal functions, wrapping the argument types in a list so that they are treated as one result instead of individual results?
@Guido:
1. There’s no need to put it into a result list. The task engine treats everything but a list as a single result. If you return a list it will add the elements in the list as individual results.
2. Wrap them in a list, so that you get[[Arg1, Arg2, Arg3]]
. Then the task engine treats[Arg1, Arg2, Arg3]
as a single result?
@Gabriel: It was. It was in a different context but yes. And i completely forgot about it :-) I’ll give this is a shot and it might work. But it does feel very strange when writing.
@Gabriel: And i can explain why it feels weird. During normal coercion (one-to-one) we do not return a list at all. As in, the coercion rule looks like this:
gm-task-match: (Coerce(), [|[ Int ]|, |[ Long ]|]) -> |[ Long ]|
@Gabriël: Vlad’s case shows the need. He interprets
task-match
as a rule that produces a single result, namely the empty list. I think he is right in this understanding. This really should be the way to understandtask-match
rules. This would work, if theRewrite
task takes this single result and boxes it in a list. By that, it ensures that Vlad’s single result is actually handled as a single result, and not as a list of no results.
Why is that weird? The semantics of result handling again:
If the returned result is a list, add each list element as a result.
Otherwise, add returned result as a result.Examples:
LongTy()
storesLongTy()
[LongTy(), IntTy()]
storesLongTy()
andIntTy()
[[LongTy(), IntTy()]]
stores[LongTy(), IntTy()]
@Guido: Yes, so just wrap it in a list yourself, instead of changing task-match? Since that might break a lot of other stuff.
If you have a
Rewrite("id", Result(1))
andResult(1)
has two results;IntTy()
andDoubleTy()
, 1.Rewrite("id", IntTy())
and 2.Rewrite("id", DoubleTy())
will be executed. Let’s say they are just identity rewrites, 1. will result inIntTy()
and 2. will result inDoubleTy()
. If you would always wrap the Rewrite result in a list you might get[IntTy()]
and[DoubleTy()]
as results, which is wrong?
@Gabriël: It simply is a leaky abstraction. The user should not be aware of the one vs. many result semantics of the task engine. He should just implement his rewrite rule. Thus, the extra list wrapping should not take place in
task-match
. Thus, it needs to be fixed in the single execution rule forRewrite(...)
.In your example, the task engine would execute Rewrite for both results, get two new result lists and combine them as always?
The current implementation:
perform-task(|nr): Rewrite(key, term) -> <task-rewrite> (key, term)
The fix:
perform-task(|nr): Rewrite(key, term) -> [<task-rewrite> (key, term)]
Why would this break many other things?
@Gabriel: besides the abstraction leak, something is still broken. It seems that nested empty lists are automatically unboxed. I’ll try to explain. For types of list of things you suggested boxing it in a list like this:
type-of(|ctx) = map(type-of(|ctx)); ![<id>]; type-is(|ctx)
Which works for functions with parameters. It turns out it does not work for functions without parameters. For something like:
... x = bar(1); Local bar(x : Int) : Int { }
The type of actual parameters of at the application site is
[ [IntTy()] ]
and things work fine. However, in the following example:... x = bar(); Local bar() : Int { }
The type of the actual parameters is only
[ ]
and not[ [ ] ]
. I can confirm that thetype-of
with the map above does get called and succeed but somewhere the nested empty list disappears.The same problem (other than the abstraction leak) occurs in my original problem from this issue. The task match needs to explicitly return lists of lists:
task-match: (BuiltInArgTypes(), (NodeTy(_), "NumNbrs")) -> [ [ IntTy() ] ]
This works fine for things that have at least one argument, but it does not for those with no arguments. For a different function:
task-match: (BuiltInArgTypes(), (NodeTy(_), "Degree")) -> [ [ ] ]
The type of the actual parameters gets unboxed. The task corresponding to the type calculation of the actual parameters is:
, ( 453 , PropCalc([[]{(Type(), Result(450))}]) , [450] , [] , None() , 2999 , 1 )
We can see that the input is
[ [ ] ]
but that the result is only[ ]
. I’m not sure how to make this explanation more clear but i’ll try to answer questions.
The builtin-lookup task corresponds to a PropLookup task not a PropCalc task? I think the problem is that PropLookup uses a variant of insert-results which removes empty lists.
The builtin-lookup is
task-match
. I use<type-match....>
.
What is the status of this?
There was an issue where the empty lists were removed during insert-results, which has been fixed. We manually wrap the arguments in another list in the rewrite task.
@Gabriël, Vlad: Can this be closed?
Yes, the API and implementation have changed drastically since then. Not a problem anymore.
Log in to post comments