3

Related to my previous question, I have tried to make a function present() for checking the presence of an optional argument. However, the following code

proc present( x ) { return x.type != void; }

proc test( a: ?T = _void )
{
    writeln();
    writeln( "test| a = ", a );
    writeln( "test| condition    = ", a.type != void );
    writeln( "test| present( a ) = ", present( a ) );

    if present( a )       // error (Line 1)
    // if a.type != void  // works (Line 2)
    {
        a = 10;
    }
}

// no optional arg
test();

// pass an optional array
var arr: [1..5] int;
test( a = arr );

writeln();
writeln( "main| arr = ", arr );

gives a compile-time error

mytest.chpl:3: In function 'test':
mytest.chpl:13: error: illegal lvalue in assignment
mytest.chpl:13: error: a void variable cannot be assigned

which says that the line a = 10; is problematic. On the other hand, if I use Line 2 instead of Line 1, the code works as expected:

test| a = 
test| condition    = false
test| present( a ) = false

test| a = 0 0 0 0 0
test| condition    = true
test| present( a ) = true

main| arr = 10 10 10 10 10 

Also, if I replace Line 1 or 2 by if isArray( a ), the code also works. Does this mean that we need to let the compiler explicitly know that the line a = 10; is not reached when a is _void? (In other words, is present() not sufficient to let the compiler know it because the test condition is "hidden" inside present()?)

roygvib
  • 7,218
  • 2
  • 19
  • 36

1 Answers1

3

Does this mean that we need to let the compiler explicitly know that the line a = 10; is not reached when a is _void? (In other words, is present() not sufficient to let the compiler know it because the test condition is "hidden" inside present()?)

Yes, that's right. The compiler needs to know at compile-time that the body of that if should be compiled only in the case that the argument not void. Putting the x.type != void check in that conditional is a reasonable solution but if you want to have a function to compute if that conditional should be evaluated, you can do so. Just mark present as a param function - which means that it returns a value that should be known at compile-time. Here is the complete example:

proc present( x ) param { return x.type != void; }

proc test( a: ?T = _void )
{
    writeln();
    writeln( "test| a = ", a );
    writeln( "test| condition    = ", a.type != void );
    writeln( "test| present( a ) = ", present( a ) );

    if present( a )
    {
        a = 10;
    }
}

// no optional arg
test();

// pass an optional array
var arr: [1..5] int;
test( a = arr );

writeln();
writeln( "main| arr = ", arr );

If you would like to read more about the language design in this area, see "The Param Return Intent" subsection in "Procedures" chapter section "Return Intents" of the language specification.

mppf
  • 1,820
  • 9
  • 9
  • I had seen a lot of `param` in various Chapel codes (on Github), but I finally understand why it's important for this kind of usage... (up to now, my usage of `param` is similar to `parameter` in Fortran (just to define a compile-time parameter). I will read the spec PDF for more details. Thanks much :) – roygvib Dec 18 '18 at 16:27