problem-solving icon indicating copy to clipboard operation
problem-solving copied to clipboard

Issues with the design of `assuming` method

Open CIAvash opened this issue 4 years ago • 2 comments

While I was working on my Curry module, I stumbled upon things that I consider issues. Now, some of them might be bugs, but most of them seem to be by design, if you look at roast; although they might be against the design documents(if I've interpreted it correctly), though that is not what defines the language.

In short, it changes function's signature and loses information and data. Maybe I don't know the reasons behind its current design, but I'll list them here to know what others think.

assuming

  1. loses the default value of optional positional parameters
    sub f1 ($a, $b = 2) {
        $a + $b;
    }
    say &f1.assuming(1).signature.raku;
    # :($b?)
    say &f1.assuming(1).signature.params[0].default.defined;
    # False
    say &f1.assuming(1)();
    # Use of Nil in numeric context
    # ...
    # 1
    
    1. removes default value of named parameters from signature of functions, but keeps its default value
      sub f2 ($a, :$b = 2) {
          $a + $b;
      }
      say &f2.signature.raku;
      # :($a, :$b = 2)
      say &f2.assuming(1).signature.raku;
      # :(:$b)
      say &f2.assuming(1).signature.params[0].default.defined;
      # False
      say &f2.assuming(1)();
      # 3
      
    2. loses default value of definite named parameters:
      sub f2_2 ($a, Int:D :$b = 2) {
          $a + $b;
      }
      say &f2_2.signature.raku;
      # :($a, Int:D :$b = 2)
      say &f2_2.assuming(1).signature.raku;
      # :(Int:D :$b)
      say &f2_2.assuming(1).signature.params[0].default.defined;
      # False
      say &f2_2.assuming(1)();
      # Parameter '$b' of routine '__PRIMED_ANON' must be an object instance of
      # type 'Int', not a type object of type 'Int'.  Did you forget a '.new'?
      # ...
      
  2. keeps the named parameter, even though the named argument was applied (roast says "Since you can override named params .assuming does not alter sig")
    sub f3 ($a, :$b) {
        $a + $b;
    }
    say &f3.assuming(:b(2)).signature.raku;
    # :($a, :$b)
    say &f3.assuming(:b(2))(1, :b(3));
    # 4
    sub f4 ($a, :$b!) {
        $a + $b;
    }
    say &f4.assuming(1).signature.raku;
    # :(:$b!)
    say &f4.assuming(:b(2)).signature.raku;
    # :($a, :$b)
    say &f4.assuming(:b(2))(1, :b(3));
    # 4
    
  3. removes parameter constraints from signature, but constraints are applied when partial function is called
    sub f5 ($a, @b where .all ~~ Int) {
        [×] $a, |@b;
    }
    say &f5.signature.raku;
    # :($a, @b where { ... })
    say &f5.signature.params[1].constraints.raku;
    # all(-> ;; $_ { #`(Block|73998640) ... })
    say &f5.assuming(2).signature.raku;
    # :(@b)
    say &f5.assuming(2).signature.params[0].constraints.raku;
    # all()
    sub f6 ($a, &b:(Int :$c!)) {
        b c => $a;
    }
    say &f6.signature.raku;
    # :($a, &b where { ... })
    say &f6.signature.params[1].constraints;
    # all(-> ;; $_ { #`(Block|77388240) ... })
    say &f6.assuming(2).signature.raku;
    # (&b)
    say &f6.assuming(2).signature.params[0].constraints;
    # all()
    
  4. doesn't set the type of a parameter whose type has been captured (roast mentions the design being incomplete), but its type will actually be checked
    sub f7 (::T $a, T $b) {
        [×] $a, $b;
    }
    say &f7.assuming(2).signature.raku;
    # ($b)
    say &f7.assuming(2).signature.params[0].type;
    # (Any)
    
  5. removes sub-signature from parameters, but type check will be done
    sub f8 ($a, @b (Int $c, Str $d)) {
        [×] $a, $c, $d;
    }
    say &f8.signature.raku;
    # :($a, @b (Int $c, Str $d))
    say &f8.signature.params[1].sub_signature.raku;
    # :(Int $c, Str $d)
    say &f8.assuming(2).signature.raku;
    # (@b)
    say &f8.assuming(2).signature.params[0].sub_signature.raku;
    # Signature
    

There might be other things I have not tried.

CIAvash avatar Oct 03 '21 11:10 CIAvash

Another case:

2.2. loses default value of definite named parameters:

sub f2_2 ($a, Int:D :$b = 2) {
    $a + $b;
}
say &f2_2.signature.raku;
# :($a, Int:D :$b = 2)
say &f2_2.assuming(1).signature.raku;
# :(Int:D :$b)
say &f2_2.assuming(1).signature.params[0].default.defined;
# False
say &f2_2.assuming(1)();
# Parameter '$b' of routine '__PRIMED_ANON' must be an object instance of
# type 'Int', not a type object of type 'Int'.  Did you forget a '.new'?
# ...

CIAvash avatar Oct 09 '21 11:10 CIAvash

In my view, these are all bugs – and should get much easier to solve with Raku AST (.assuming really wants to be a macro!) See this stack overflow question for some related discussion.

codesections avatar Nov 09 '21 14:11 codesections