[m-dev.] Re: Documentation of support for polymorphic pragma c code

Fergus Henderson fjh at cs.mu.oz.au
Wed Jan 14 15:08:10 AEDT 1998


On 14-Jan-1998, Oliver Hutchison <ohutch at students.cs.mu.oz.au> wrote:
> 
> On Wed, 14 Jan 1998, Fergus Henderson wrote:
> 
> > The interface is the same whether the predicate is monomorphic or polymorphic.
> 
> Not quite. If the pred is polymorphic c variables holding type infos for
> each of the type variables will also be present. Is this the undocument
> feature you mention below? 

Yes.

> > If you want to get access to the type_infos, then as the documentation
> > in the "Calling Mercury code from C" section says:
> > 
> > 	... `type_info' arguments can be obtained using the Mercury
> > 	`type_of' function in the Mercury standard library module `std_util'.
> > 
> > (Well, OK, I admit it --- there is an undocumented alternate way of obtaining
> > them.  However, using `type_of' works fine, and is arguably more elegant,
> > so I thought it better not to document the alternative.)
> 
> > I suppose we could add a similar statement to the above documentation
> > in the "Calling C code from Mercury" section.  Perhaps something like
> > 	
> > 	Note that `pragma c_code' can be used for both polymorphic and
> > 	ordinary (monomorphic) predicates.  When defining polymorphic
> > 	predicates, you may sometimes need access to the `type_info'
> > 	values which provides information about the particular types
> > 	passed.  These can be obtained using the Mercury `type_of'
> > 	function in the Mercury standard library module `std_util'.
> > 	You can write a small wrapper predicate which calls `type_of'
> > 	to obtain the type_info for its arguments and then passes the
> > 	results to the predicate implemented using `pragma c_code'.
> 
> Well I guess that is ok but I don't really agree that it is a particularly
> elegant way of doing it. IMHO adding the extra variables to the c_code is
> the elegant/intuitive way.

> Using wrappers is simply forcing the programmer
> to do what is already done!

Well, we could change that easily enough -- by deleting the undocumented
feature.  Then the compiler would be able to optimize away the passing
of type_info arguments to `pragma c_code' procedures, so the
wrappers would not be duplicating what is already done ;-)

> Given the following code (I think this is what
> you have in mind?) : 
> 
> :- pred fug(T1, T2).
> :- mode fug(in, out) is det.
> 
> fug(A, B) :-
> 	TypeInfo_for_T1 = type_of(A),
> 	TypeInfo_for_T2 = type_of(B),
> 	fug2(TypeInfo_for_T1, TypeInfo_for_T2, A, B).
> 
> :- pred fug2(type_info, type_info, T1, T2).
> :- mode fug2(in, out, in, out) is det.
> 
> :- pragma c_code(fug2(TypeInfo_for_T1::in, TypeInfo_for_T2::in, A::in,
> 		B::in), "
> 	do_some_stuff(TypeInfo_for_T1, TypeInfo_for_T2, A, B);

Basically yes.  But I'd write it as

	:- pred fug(T1::in, T2::out) is det.
	fug(A, B) :-
		fug2(type_of(A), type_of(B), A, B).

	:- pred fug2(type_info::in, type_info::out, T1::in, T2::out) is det.
	:- pragma c_code(fug2(TypeInfo1::in, TypeInfo2::in, A::in, B::in), "
		do_some_stuff(TypeInfo1, TypeInfo2, A, B);
	").

which is a few lines shorter.

Note that if this is the only use of fug2/4, then it will be inlined.
If type_of/1 were recognized by the compiler as a builtin, then
there should be no efficiency difference.  (Currently it is not,
so there may be a few additional instructions, but the efficiency
difference would be small.)

> could be written 
> 
> :- pred fug(T1, T2).
> :- mode fug(in, out) is det.
> 
> :- pragma c_code(fug(A::in, B::in) ,"
> 	do_some_stuff(TypeInfo_for_T1, TypeInfo_for_T2, A, B);
> ").
> 
> I know I like the second alternative.

Here's the disadvantages that I see for the second alternative:

	- it requires us to reserve more of the user's namespace
	  (as you observed, the user had better be careful to avoid names
	  of the form `TypeInfo_for_*')

	- when reading the code, the second alternative may be
	  more difficult to understand, particularly if you aren't
	  aware of (or have forgotten about) this language feature.
	  All you see is these variable names `TypeInfo_for_T1'
	  with no indication of how they are initialized.
	  In contrast, with the first alternative, the call to type_of/1
	  is explicit, and the user can easily look up the documentation
	  for type_of/1 if they don't know what it does.

> Also if you have a look at the
> generated c code for each of the alternatives you will see that the second
> way of doing it produces a lot less code. Oh and the first way produces a
> bug in the generated c code too (The variable names TypeInfo_for_T? are
> duplicated).

These are both implementation details which could be fixed.

You're probably right that *given the current implementation*
the second alternative is more elegant, but I think that what
we should do is to pick the interface that is most elegant,
and then adapt the implementation to suit that interface,
rather than adapting the interface to suit the current implementation.

-- 
Fergus Henderson <fjh at cs.mu.oz.au>   |  "I have always known that the pursuit
WWW: <http://www.cs.mu.oz.au/~fjh>   |  of excellence is a lethal habit"
PGP: finger fjh at 128.250.37.3         |     -- the last words of T. S. Garp.



More information about the developers mailing list