Type-bound procedure and procedure pointer component calls

Daniel Kraft d@domob.eu
Tue Aug 26 14:51:00 GMT 2008


Hi Janus,

thanks for the comments!

Janus Weil wrote:
>> Add a new ref-type REF_PROC or extend REF_COMPONENT with an attribute to
>> hold an actual arglist; then in match_varspec, if a component symbol is
>> found that is in the type-bound procedures namespace, parse an arglist
>> following it and build such a REF_PROC:
>>
>> WRITE (*,*) val(1)%tbp_function (42)
>>
>> will become
>>
>> EXPR_VARIABLE(val) -> REF_ARRAY(1) -> REF_PROC(arglist(42), gfc_typebound*)
> 
> Sounds good. Alternatively the arglist could be stored in the top
> level gfc_expr, which already has a field for it
> (expr->value.function.actual). Then I think we also need a new
> expression type (EXPR_SUBROUTINE?) for the case that the TBP/PPC is a
> subroutine. For functions we can probably reuse the existing
> EXPR_FUNCTION.

Actually, so far I thought about the gfc_expr only as a means to reuse 
match_varspec and until we do something with the matched data after that 
in parsing or resolution.  I don't quite like the idea of gfc_expr 
holding a SUBROUTINE "officially".  This from my point of view somewhat 
defeats the purpose of an "expression".  OTOH of course, this makes 
handling a bit easier.

I'd rather go for using EXPR_FUNCTION for both subroutines and functions 
and allow the exception that gfc_code->expr of a CALL statement can/must 
be an EXPR_FUNCTION expression referencing a SUBROUTINE.  As for the 
arglist, if we do EXPR_FUNCTION it is of course a good idea to reuse 
value.function.actual (if we use another type, I don't think its a good 
idea to use the function-specific union).

I just realize that for EXPR_FUNCTION the symtree member will be treated 
as the function to call, won't it?  Thus it is probably safer to use a 
new expr-type for "component-calls".

>> During resolution, we can transform such an expression easily into an
>> ordinary function call; the passed-object will be given by the expression
>> itself with the last reference removed, and the other things needed for the
>> call (the binding-target procedure and the arglist) are in the REF_PROC.
> 
> Ok. However, this "transforming to ordinary function call" does not
> work for PPCs of course. There we need dynamic calling, which will
> also be necessary for TBPs later to have fully dynamic polymorphism
> (once the other OOP bits are in place). So, at *some* point this will
> have to be implemented in a dynamic way. The question is: Should we
> already do this now, or rather start with a static transformation at
> resolution stage? The advantage of the dynamic approach would be that
> it's more or less the same for both TBPs and PPCs, so that we
> hopefully need only one implementation. And we wouldn't have to change
> it later for full OOP.

Agreed.  However, for dynamic dispatch and TBPs to work, we need Paul's 
CLASS implementation.  Until then, I think for TBPs it will be best to 
implement them at first the quick way and work out a dynamic 
implementation later; at least I do want to look how big the patch gets 
and how easy such an implementation will be.

But of course it is good to find a common strategy that can be used for 
that implementation and for PPCs.  If we use a new expr-type as 
suggested above, it should not be too hard to integrate it into the 
trans-phase with whatever implementation we need for it, I think.  That 
could be something like:

expr.expr_type = EXPR_COMPCALL;
expr.symtree = ...; expr.ref = ...;
expr.value.compcall.actual = arglist;
expr.value.compcall.derived = derived;
expr.value.compcall.comp = comp;

Where symtree/ref contain the originally parsed ref-chain leading to the 
called component, arglist is the actual arglist that is still resolved 
to contain the passed-object during resolution, derived is the declared 
derived-type of the passed-object and comp is the called component, 
either as symtree for TBPs or gfc_component for PPCs (some way to store 
it at least).

This would not change any existing code in respect to EXPR_FUNCTION of 
course and we would "simply" have to implement trans of EXPR_COMPCALL 
the way we need to do it.  If possible (for now and maybe 
NON_OVERRIDABLE methods or something like this) we could also handle 
EXPR_COMPCALL in resolution.

For PPCs, we need to extend the expr.value.compcall structure and do the 
right trans'ing, but otherwise it should be fine?

>> For CALL's, we could add a new field
>>
>> gfc_expr* tbp;
>>
>> to gfc_code.  If not NULL it will hold such a reference-expression as above
>> encapsulating the TBP-call.  Once again, during resolution this will be
>> transformed into an ordinary CALL of a SUBROUTINE.
> 
> Do you think an extra field is necessary? gfc_code already has two
> gfc_expr fields ("expr" and "expr2"), none of which is being used for
> CALL. And the type of the expression will in any way be indicated by
> expr->expr_type (EXPR_SUBROUTINE/EXPR_FUNCTION/etc).

To implement CALL's, we need a way to distinguish between ordinary calls 
and component calls, too, maybe a flag or another EXEC_ type (I'm not 
sure how much change this would mean).  Then once more again, in trans 
look at the type and either call the referenced symtree as we do now or 
call the EXPR_COMPCALL stored in expr.

> Maybe it would be a good idea to start with a patch that changes the
> way that ordinary functions and subroutines are called (by using
> gfc_expr instead of gfc_symtree), so that this can more easily be
> extended to TBPs and PPCs.

If we do so, we could as well call them through the completely new 
gfc_callee structure, couldn't we?  If we don't want to go through all 
that code changes needed to accomplish that, I think we should stick to 
only extending by new means to call components with dynamic dispatching 
as written above.  What would you change and what would you leave?

> Maybe some of the more experienced gfortraners could try to comment on
> all of this. I'm not sure if I'm overlooking all the consequences of
> our design decisions right now.

That's a very good idea indeed :D

BTW, why can't we transform PPC-calls to calls to ordinary 
procedure-pointers with adapted arglist?  I have to admit though that I 
know nearly nothing about procedure-pointers in Fortran nor about your 
implementation of them.

So far,
Daniel

-- 
Done:     Arc-Bar-Cav-Sam-Val-Wiz, Dwa-Elf-Gno-Hum-Orc, Law-Neu-Cha, Fem-Mal
To go:    Hea-Kni-Mon-Pri-Ran-Rog-Tou



More information about the Fortran mailing list