RE: Meta-called do loops and setarg

From: Stefano Novello <stefano.novello_at_parc-technologies.com>
Date: Thu 29 May 2003 06:33:44 PM GMT
Message-ID: <3E899FAFBF56D611B6A500508B9A9DA206E27C@LON-SRV2>
I agree that the use of setarg is ugly, but sometimes you really do need
something like it.

There are a couple of solutions.

1) Currently our pattern for something changeable is to declare a struct,
and write accessors like <struct>_set_<field> that in their simplest form
just call setarg.

e.g.
s_set_f(Struct,Val) :-
	setarg(f of s, Struct, changeable(Val)).	% use changeable to
avoid sharing issues
								% mentioned
in setarg/3 help page

We could have a different pattern, that always had a variable with a
tentative value. The
tentative value would be logically updated and then set with tent_set. 
s_set_f(S,Val) :-
	S tent_get SS,
	update_struct(s,[f:Val],SS,SS1),
	S tent_set SS1.

This adds some nice features, like you can do better data-driven stuff by
waking on change of tentative value. This is a slightly different use of the
repair library, and might necessitate things like specific copy/unify
handlers depending on the functor of the tentative value.
I think it solves the referential integrity issue though.

This does not help in the case of large arrays or hash tables. In that case,
not having setarg would be too expensive, trading off an O(1) (single
element update) operation with
an O(N) operation of copying the whole array, or O(logN) set and get as in
tree implementations of arrays.

In the case of very large structures we still need something like setarg. My
preferred solution here would be a differently tagged kind of compound term.
You would be able to set properties of such compound terms, such as whether
it can be modified, or how the system should behave when you try to copy the
term. 
This would not solve the referential transparency problem but would localise
the setarg pattern to just those places where it is needed, and where
something is explicitly created as modifiable.

On meta-called do-loops.
In my opinion, I believe the metacall implementation if do/2 ought simply to
raise an error.
The reason are:
1) There should always be away of avoiding such a meta-call, 
2) We don't want to encourage people to construct and call do loops on the
fly and then complain
about their performance
3) All over the system we have the property that meta-called behavior is
identical to compiled behavior, (with a roughly constant meta-call
overhead). Here the overhead, varies dramatically and unexpectedly with the
supplied data, and the behaviour is not identical if you are using ==/2 or
setarg/3, and maybe other non-logical things I have not thought of. I would
say if eclipse supports metacall of do/2, these differences in behaviour
have to be carefully documented, but this seems to me a waste of time, much
better to document that a metacall of do/2 raises an error. For
compatibility call_do/2 might be defined for people that rely on the
meta-called behaviour, although I doubt anybody really requires this.

Stefano


-----Original Message-----
From: Joachim Schimpf [mailto:j.schimpf@icparc.ic.ac.uk]
Sent: 29 May 2003 15:23
To: josh singer
Cc: 'eclipse-bugs@icparc.ic.ac.uk'; Stefano Novello; Mark Wallace
Subject: Re: Meta-called do loops and setarg


Hi Josh,

in brief, the solution is to remove setarg/3 from the language.
We can put this on the plan for a future release.

Unfortunately, it is very difficult to reconcile constant
demands for impure, low-level features with an aspiration
to keep the language semantics simple and clean.

When you use setarg/3, you destroy the referential transparency
property and simple notion of identity that you otherwise have
in logic programming (the man page for setarg/3 tries to say
that in its own clumsy ways).

In your example, this 'feature' of setarg/3 allows you to construct
a program that behaves differently, depending on the time (compile
vs call time) at which the loop is translated into its recursive
equivalent:

In query 1, the effective loop is, as written,

  (count(I, 1, 4), param(X) do setarg(1, X, I)

In query 2, X is already substituted, and the effective loop is

  (count(I, 1, 4), param(p(0, Y)) do setarg(1, p(0, Y), I))

which is equivalent to

  (count(I, 1, 4), param(Y) do setarg(1, p(0, Y), I)

and explains the observed behaviour.

Since setarg/3 breaks such a fundamental property, loops are surely
not the only context in which you can construct weird behaviours.
It is therefore quite important to limit and localise the use of
setarg/3 as much as possible, while we still support it.

Cheers,
--Joachim


josh singer wrote:
> 
> Hi folks,
> 
> Look at the following example, run on v 5.6 #28, Linux. With each
iteration
> of the do loop the first param of X gets set to a higher number. Fine.
> 
> But if we meta-call the do loop, the setargs appear not to have any
effect.
> Seems like a bug. The bug has been there at least since 5.4.
> 
> Wierdly, if you instantiate Y first, the bug goes away.
> 
> cheers,
> 
> josh
> 
> ----
> 
> ECLiPSe Constraint Logic Programming System [kernel]
> Copyright Imperial College London and ICL
> Certain libraries copyright Parc Technologies Ltd
> GMP library copyright Free Software Foundation
> Version 5.6 #28, Mon Apr 21 00:13 2003
> [eclipse 1]:  X = p(0, Y), (count(I, 1, 4), param(X) do setarg(1, X, I)).
> 
> Y = Y
> X = p(4, Y)
> I = I
> Yes (0.00s cpu)
> [eclipse 2]:  X = p(0, Y), call((count(I, 1, 4), param(X) do setarg(1, X,
> I))).
> 
> Y = Y
> X = p(0, Y)
> I = I
> Yes (0.00s cpu)
> [eclipse 3]:

-- 
 Joachim Schimpf              /             phone: +44 20 7594 8187
 IC-Parc                     /      mailto:J.Schimpf@imperial.ac.uk
 Imperial College London    /    http://www.icparc.ic.ac.uk/eclipse
Received on Thu May 29 19:31:03 2003

This archive was generated by hypermail 2.1.8 : Wed 16 Nov 2005 06:08:22 PM GMT GMT