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:

		(BuiltInArgTypes(), (NodeTy(_), "NumNbrs")) -> []

Given the above the message always shows up. I can confirm that the task-match above actually gets called and that the farg-ty task executed successfully and produces the empty list. If i change it to:

		(BuiltInArgTypes(), (NodeTy(_), "NumNbrs")) -> ["foo"]

Then the message no longer appears.

This makes me to believe that [ ] as a task result is treated as task failure. Maybe this is conceptually related to https://yellowgrass.org/issue/NaBL/50.

Submitted by Vlad Vergu on 9 July 2013 at 18:11

On 9 July 2013 at 18:14 Gabriël Konat commented:

It treats an empty list as failed, why is that an error?

On 9 July 2013 at 18:21 Vlad Vergu commented:

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?

On 9 July 2013 at 18:27 Gabriël Konat commented:

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?

On 9 July 2013 at 18:30 Vlad Vergu commented:

Yes that is the error. I’m not sure what you mean by wrapping the argument types. Suggesting:

   (BuiltInArgTypes(), (NodeTy(_), "NumNbrs")) -> [ [ ] ]

? This seems a bit weird, but might work.

On 9 July 2013 at 18:34 Guido Wachsmuth commented:

I think these are two issues:

  1. 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.
  2. 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.

On 9 July 2013 at 18:38 Gabriël Konat commented:

@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?
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?

On 9 July 2013 at 18:40 Vlad Vergu commented:

@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.

On 9 July 2013 at 18:43 Vlad Vergu commented:

@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   ]|

On 9 July 2013 at 18:46 Guido Wachsmuth commented:

@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 understand task-match rules. This would work, if the Rewrite 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.

On 9 July 2013 at 18:48 Gabriël Konat commented:

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.

LongTy() stores LongTy()
[LongTy(), IntTy()] stores LongTy() and IntTy()
[[LongTy(), IntTy()]] stores [LongTy(), IntTy()]

On 9 July 2013 at 18:48 Gabriël Konat commented:

@Guido: Yes, so just wrap it in a list yourself, instead of changing task-match? Since that might break a lot of other stuff.

On 9 July 2013 at 18:52 Gabriël Konat commented:

If you have a Rewrite("id", Result(1)) and Result(1) has two results; IntTy() and DoubleTy(), 1. Rewrite("id", IntTy()) and 2. Rewrite("id", DoubleTy()) will be executed. Let’s say they are just identity rewrites, 1. will result in IntTy() and 2. will result in DoubleTy(). If you would always wrap the Rewrite result in a list you might get [IntTy()] and [DoubleTy()] as results, which is wrong?

On 9 July 2013 at 19:10 Guido Wachsmuth commented:

@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 for Rewrite(...).

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?

On 9 July 2013 at 20:00 Vlad Vergu commented:

@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 the type-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.

On 9 July 2013 at 20:13 Gabriël Konat commented:

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.

On 9 July 2013 at 20:17 Vlad Vergu commented:

The builtin-lookup is task-match. I use <type-match....>.

On 24 July 2013 at 00:44 Guido Wachsmuth commented:

What is the status of this?

On 26 July 2013 at 22:27 Gabriël Konat commented:

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.

On 19 January 2014 at 01:36 Guido Wachsmuth commented:

@Gabriël, Vlad: Can this be closed?

On 19 January 2014 at 09:57 Vlad Vergu commented:

Yes, the API and implementation have changed drastically since then. Not a problem anymore.

On 19 January 2014 at 09:57 Vlad Vergu closed this issue.

Log in to post comments