Home > Archive > Fortran > April 2007 > limitations on function reference
You are viewing an archived Text-only version of the thread.
To view this thread in it's original format and/or if you want to reply to
this thread please [click here]
| Author |
limitations on function reference
|
|
| John Harper 2007-04-23, 10:04 pm |
| AFAIK if f(x) is an array-valued function one can't access an element
by saying (for example)
PRINT *,f(x)(1)
but must be more long-winded, by declaring an array g of the same shape
as f, with elements of the same type, and then saying
g = f(x)
PRINT *,g(1)
If f is of type character one could also imagine 3 pairs of parentheses:
PRINT *,f(x)(1:2)(3:4)
to print characters 3 and 4 of elements 1 and 2 of the array f(x)
Does some possible ambiguity I haven't thought of prevent allowing
that sort of thing?
-- John Harper, School of Mathematics, Statistics and Computer Science,
Victoria University, PO Box 600, Wellington 6140, New Zealand
e-mail john.harper@vuw.ac.nz phone (+64)(4)463 5341 fax (+64)(4)463 5045
| |
|
| It may be convenient to write something like f(x)(i) but when it comes to debugging, you'll just run into the same problems as C++ i.e. there is no way of telling what f(x) returns. I have to deal with this sort of thing everyday and it is really difficult to debug code when someone who likes one liners writes something (in C++) like
return (*(func1(jj)->xx)[kk])[2];
It is great when it works, but when it doesn't, you're stuck. You have to find out what func1(jj) is returning before you can proceed with the rest of it. Since getting it into a temp variable and coding it like that should generate a similar amount of code.
Why not think of the poor sod who has to debug this and assign it to a temp variable. It may look slick but it takes longer to understand. You may understand it now but try coming back to it after 2 years. Takes a while to figure out this type of code. | |
| glen herrmannsfeldt 2007-04-24, 8:04 am |
| John Harper wrote:
> AFAIK if f(x) is an array-valued function one can't access an element
> by saying (for example)
> PRINT *,f(x)(1)
> but must be more long-winded, by declaring an array g of the same shape
> as f, with elements of the same type, and then saying
> g = f(x)
> PRINT *,g(1)
> If f is of type character one could also imagine 3 pairs of parentheses:
> PRINT *,f(x)(1:2)(3:4)
> to print characters 3 and 4 of elements 1 and 2 of the array f(x)
One ambiguity is just the one you mention: that between arrays
and substrings. If you allow such, you might also allow substrings
of substrings, in which case there is definitely an ambiguity.
> Does some possible ambiguity I haven't thought of prevent allowing
> that sort of thing?
Note that in C, subscripting is an operator, and can be applied
to any pointer variable or pointer expression. In that case,
an array name can be considered a pointer constant. The return
value of a pointer valued function can be subscripted. In C,
the () of a function call are also an operator, and can be
applied to function pointer valued functions, for example.
Using a function for substrings removes some of the ambiguity
and allows substrings of substrings in languages like PL/I.
-- glen
| |
| highegg 2007-04-24, 8:04 am |
| On Apr 24, 4:25 am, har...@mcs.vuw.ac.nz (John Harper) wrote:
> AFAIK if f(x) is an array-valued function one can't access an element
> by saying (for example)
> PRINT *,f(x)(1)
> but must be more long-winded, by declaring an array g of the same shape
> as f, with elements of the same type, and then saying
> g = f(x)
> PRINT *,g(1)
>
> If f is of type character one could also imagine 3 pairs of parentheses:
> PRINT *,f(x)(1:2)(3:4)
> to print characters 3 and 4 of elements 1 and 2 of the array f(x)
>
> Does some possible ambiguity I haven't thought of prevent allowing
> that sort of thing?
If you need the idiom regularly, you can define (and possibly
overload) a function
TAKE(array,index) that simply returns array(index) and use
PRINT *,TAKE(f(x),1)
Such manipulation function like this TAKE (or SWAP and others) perhaps
could be added to the Fortran standard. Admittedly there is little
benefit; OTOH, the cost of adding intrinsics is really low.
| |
| Daniel Franke 2007-04-24, 8:04 am |
| John Harper wrote:
> AFAIK if f(x) is an array-valued function one can't access an element
> by saying (for example)
> PRINT *,f(x)(1)
> but must be more long-winded, by declaring an array g of the same shape
> as f, with elements of the same type, and then saying
> g = f(x)
> PRINT *,g(1)
>
> If f is of type character one could also imagine 3 pairs of parentheses:
> PRINT *,f(x)(1:2)(3:4)
> to print characters 3 and 4 of elements 1 and 2 of the array f(x)
An equally upsetting non-feature is:
TYPE :: atype
INTEGER :: a
END TYPE
TYPE(a) FUNCTION f(a)
print *, f(42)%a
^
which is not allowed (asked gfortran, ifort and f95). Accessing only a
single member of a returned type would come in handy at some times.
| |
| highegg 2007-04-24, 7:05 pm |
| On Apr 24, 12:21 pm, Daniel Franke <nos...@nowhere.com> wrote:
> John Harper wrote:
>
>
> An equally upsetting non-feature is:
>
> TYPE :: atype
> INTEGER :: a
> END TYPE
> TYPE(a) FUNCTION f(a)
>
> print *, f(42)%a
> ^
>
> which is not allowed (asked gfortran, ifort and f95). Accessing only a
> single member of a returned type would come in handy at some times.
Sometimes, yes, but is it worth the effort of modifying the language?
You can easily write an extracting function if you need the idiom
often, or use a temporary.
| |
| Dick Hendrickson 2007-04-24, 7:05 pm |
| John Harper wrote:
> AFAIK if f(x) is an array-valued function one can't access an element
> by saying (for example)
> PRINT *,f(x)(1)
> but must be more long-winded, by declaring an array g of the same shape
> as f, with elements of the same type, and then saying
> g = f(x)
> PRINT *,g(1)
>
> If f is of type character one could also imagine 3 pairs of parentheses:
> PRINT *,f(x)(1:2)(3:4)
> to print characters 3 and 4 of elements 1 and 2 of the array f(x)
>
> Does some possible ambiguity I haven't thought of prevent allowing
> that sort of thing?
I don't think it is ambiguous, but it surely can become hard to
understand for a person.
A couple of thoughts.
1) You're cheating by using "x" as an argument ;). Try 42 instead
and then there are a ton of things that someone might try to write
(ch* is character, *f is function, *a* is an array):
chf(42) af(42) cha(42) a(42)
chf(42)(1) af(42)(1) cha(42)(1) a(42)(1)
chf(42)(1:3) af(42)(1:3) cha(42)(1:3) a(42)(1:3)
chf(42)(1)(2:3) af(42)(1)(2:3) cha(42)(1)(1:3) a(42)(1)(2:3)
chf(42)(1:3)(2:4)
I think everything is unambiguous, but it's a dog's breakfast and
likely to be error prone, especially if the function doesn't
have arguments.
2) It's hard to limit this to functions. A function is just an
expression with one term. The regularity police will "demand"
that this be applied to general expressions.
(x(I)(J:K)+y(L)(2))(M:N)
just doesn't look worthwhile.
3) This came up for a little discussion during the initial array
processing design in the late 80's and was discarded (I don't
remember why). It hasn't been reproposed by anybody willing to
do the (hard?) initial design work. I'd guess that the belief is
that the (perceived) problems outweigh the expected benefit.
Dick Hendrickson
>
> -- John Harper, School of Mathematics, Statistics and Computer Science,
> Victoria University, PO Box 600, Wellington 6140, New Zealand
> e-mail john.harper@vuw.ac.nz phone (+64)(4)463 5341 fax (+64)(4)463 5045
>
>
| |
| Beliavsky 2007-04-24, 7:05 pm |
| On Apr 23, 10:25 pm, har...@mcs.vuw.ac.nz (John Harper) wrote:
> AFAIK if f(x) is an array-valued function one can't access an element
> by saying (for example)
> PRINT *,f(x)(1)
> but must be more long-winded, by declaring an array g of the same shape
> as f, with elements of the same type, and then saying
> g = f(x)
> PRINT *,g(1)
To slice an expression one could define a function
function slice(ivec,i1,i2) result(jvec)
! return the slice ivec(i1:i2), avoiding out-of-bounds
! array access
integer, intent(in) :: ivec(:)
integer, intent(in) :: i1,i2
integer, allocatable :: jvec(:)
integer :: j1,j2,nj
j1 = max(lbound(ivec,dim=1),i1)
j2 = min(ubound(ivec,dim=1),i2)
nj = j2 - j1 + 1
allocate (jvec(nj))
jvec = ivec(j1:j2)
end function slice
and write
slice(f(x),i1,i2)
One can also write a function that gets a component of a derived type,
to which an expression could be passed. It would be convenient to make
such a function ELEMENTAL.
An advantage of writing a function is that one can check that the
slice is within the bounds of the array.
>
> If f is of type character one could also imagine 3 pairs of parentheses:
> PRINT *,f(x)(1:2)(3:4)
> to print characters 3 and 4 of elements 1 and 2 of the array f(x)
>
> Does some possible ambiguity I haven't thought of prevent allowing
> that sort of thing?
Octave (and I assume Matlab) allow this, as does R, with slightly
different syntax. Here is an example.
octave:1> x = [10,20,30]
x =
10 20 30
octave:2> y = x(2:3)(2)
y = 30
I agree it would be a convenient feature to have in Fortran if it does
not break something, but I don't deem it essential.
>
> -- John Harper, School of Mathematics, Statistics and Computer Science,
> Victoria University, PO Box 600, Wellington 6140, New Zealand
> e-mail john.har...@vuw.ac.nz phone (+64)(4)463 5341 fax (+64)(4)463 5045
| |
| Dick Hendrickson 2007-04-24, 7:05 pm |
| Beliavsky wrote:
> On Apr 23, 10:25 pm, har...@mcs.vuw.ac.nz (John Harper) wrote:
>
> To slice an expression one could define a function
>
> function slice(ivec,i1,i2) result(jvec)
> ! return the slice ivec(i1:i2), avoiding out-of-bounds
> ! array access
> integer, intent(in) :: ivec(:)
> integer, intent(in) :: i1,i2
> integer, allocatable :: jvec(:)
> integer :: j1,j2,nj
> j1 = max(lbound(ivec,dim=1),i1)
This sort of works, but it's not very convenient.
The lower bound of an assumed shape array, like IVEC(:), is
always 1.
So, if f(x) doesn't return a 1-based subscripted array, the
caller will have to pass in the lower bound, or do arithmetic on
i1 and j1 on the call side.
Dick Hendrickson
> j2 = min(ubound(ivec,dim=1),i2)
> nj = j2 - j1 + 1
PS: I'd worry a little here about trying to get a zero sized slice.
I think everything works, but I'd probably stick in an
nj = max(nj,0)
just to be sure.
> allocate (jvec(nj))
> jvec = ivec(j1:j2)
> end function slice
>
> and write
>
> slice(f(x),i1,i2)
>
> One can also write a function that gets a component of a derived type,
> to which an expression could be passed. It would be convenient to make
> such a function ELEMENTAL.
>
> An advantage of writing a function is that one can check that the
> slice is within the bounds of the array.
>
>
> Octave (and I assume Matlab) allow this, as does R, with slightly
> different syntax. Here is an example.
>
> octave:1> x = [10,20,30]
> x =
>
> 10 20 30
>
> octave:2> y = x(2:3)(2)
> y = 30
>
> I agree it would be a convenient feature to have in Fortran if it does
> not break something, but I don't deem it essential.
>
>
>
|
|
|
|
|