On Fri, 19 Jun 2015, Sven Schreiber wrote:
Am 19.06.2015 um 22:09 schrieb Allin Cottrell:
>
> But the data are _not_ gone, or not after the change I made in February
> of this year. If you don't assign the return value of moo(), nothing
> changes in the caller's dataset.
I don't really understand why the behavior should so crucially depend on
whether there is an explicit assignment to a new list object or not.
Because it's the list _members_ (or their names) that produce the side
effects, not the new list name itself. So if I do:
list newlist = some_list_returning_function()
and one of the list members is called 'cool' and I happened to have a
series 'cool' already in my dataset, then it is overwritten. How am I
supposed to know what the function uses for the names of returned list
members?
AFAICS this has always been a problem with using lists. Exceptional, as
Jack said, yes; but not new. Or am I too tired and missing something?
So I don't see this February change as a solution.
>
> IMO that's not a reason to stop using lists. But I think it _is_ a
> reason to resist Sven's suggestion that the error resulting from giving
> an anonymous, on-the-fly, function-returned list as a function argument
> is a gretl bug. I thought it was a bug, at face value, but now I don't
> think so; I believe it's a defensible safeguard. However, the resulting
> error message should be clearer.
Better error message, yes absolutely. But see above, how is the explicit
assignment requirement really a safeguard? I'm puzzled.
OK, let me try to explain -- this is not particularly obvious unless
you have pored over the internals of gretl lists at length, as I have.
1) We have some built-in functions that return lists. For example,
log() and dummify(). Hopefully, it is clear that these functions may
add several series to the caller's dataset, and the documentation for
these functions should make clear what names the added series will
bear. If you use one of these functions and are surprised by the
results (e.g. "How come my pre-existing series l_x got overwritten?"
when calling log()), you just haven't bothered to read the doc for the
function you're calling.
2) If and when a contributed function package returns a list, it
should be just as explicit as the built-in functions with regard to
the character and naming of the series members of the returned list.
Again, there should be no surprises for anyone who has read the doc. I
would regard violation of this principle as sufficient reason to
reject a function package.
Now, please note that the function calls I have in mind in relation to
1) and 2) above would typically look like:
list Lx = log(x) # built-in
list Dx = dummify(x) # built-in
list Fx = fooify(x) # notional contributed function
But there are two other possible cases:
(i) A plain, unassigned call to a function, as in
fooify(x)
and (ii), a function call to create an anonymous argument for a
further function, as in
y = somefun(fooify(x))
where we suppose that fooify() returns a list.
Case (i) is (I would say) artificial, but case (ii) is an instance of
the sort of thing you noted in the post that started this thread. In
both cases, what I'm concerned about is the possible side-effect.
Here's the fork: such calls either (a) do nothing, or (b) they
(potentially) add series to the caller's dataset unbidden. If they do
nothing, then case (ii) fails, which is the "bug" you raised. But
otherwise they must add series to the main dataset _even though the
user has not called for any such thing_. That is, the user has neither
assigned the return value from the function, nor has he/she poked in a
"pointer"-type argument which could cause changes in a variable at the
caller level.
In my opinion a hansl function should never produce any changes in the
caller's data other than via assignment of a return value or
modification of an argument given in pointer form ("commands" are a
different matter). It's a somewhat unfortunate (but, I think,
unavoidable) consequence of this that you can't call a function to
create an on-the-fly, anonymous list to serve as an argument to
another function.
Allin