maple

has([_passed],'op1') is acting weird with boolean parameters


I'm trying to manage optional parameters (I need to know which of them are actually passed), but it seems like in the case of boolean type has([_passed],'op1') is acting weird. Can someone explain why has([_passed],'op1') is working correctly in function f, but isn't working correctly in function g? What am I missing here?

f:=proc(x,{op1::integer:=1,op2::boolean:=false});
   print(has([_passed],'op1'),has([_passed],'op2'));
end proc:
g:=proc(x,{op1::boolean:=true,op2::boolean:=false});
  print(has([_passed],'op1'),has([_passed],'op2'));
end proc:
 
 "Correct:";
 f(x);
 f(x,op1=1);
 f(x,op2=true);
 f(x,op1=1,op2=true);
 "Incorrect:";
 g(x);
 g(x,op1=true);
 g(x,op2=true); #this case gives incorrect result
 g(x,op1=true,op2=true);

The output:


                              "Correct:"
                             false, false
                             true, false
                             false, true
                              true, true
                             "Incorrect:"
                             false, false
                             true, false
                              true, true
                              true, true

The idea of has([_passed],'op1') is taken from this post.


Solution

  • Printing out _passed[1.._npassed] reveals what has happened here.

    g:=proc(x,{op1::boolean:=true,op2::boolean:=false});
      print(has([_passed],'op1'),has([_passed],'op2'),[_passed[1.._npassed]]);
    end proc:
    
    g(x,op2=true);
    

    gives true, true, [x, op2 = true]. So the first true from has([_passed],'op1') is because 'op1' is evaluated as true and not as the name op1. And indeed _passed has true, the true in op2 = true. This can be verified by using extra unevaluation quotes:

    g:=proc(x,{op1::boolean:=true,op2::boolean:=false});
      print(has([_passed],''op1''),has([_passed],'op2'),[_passed[1.._npassed]]);
    end proc:
    
    g(x,op2=true);
    

    now gives the expected false, true, [x, op2 = true].

    Relying on the correct number of unevaluation quotes is fragile. As noted in the comment by @Nasser, one can use default values to find when an ordered or keyword argument was passed, recognizing that the default value does not have to be the declared type. For example,

    g:=proc(x,{op1::truefalse:=0,op2::truefalse:=0});
      if op1=0 then
         print("user passed no value")
      else
         print(op1)
      end if
    end proc:
    
    g(x,op2=true); 
    

    gives "user passed no value". (I used truefalse rather than boolean here because the latter can include other than true or false, such as 2 > 3.)