title: Perl 6 and `multi method new`
body: <p>I have a class <code>Price</code> that encapsulates an <code>Int</code>. I also would like it to have constructors for <code>Num</code> and <code>Str</code>. I thought I could do this by making <code>Price::new</code> a multi method with various type constraints, but this isn't the behavior I expected. It looks like <code>Price.new</code> is skipping the constructor altogether and going straight to <code>BUILD</code>, bypassing the casting logic.</p>
  
  <p>I know from looking at other Perl 6 code that using <code>multi method new</code> is acceptable. However, I haven't been able to find an example of a polymorphic constructor with different type constraints. How do I rewrite this code to force it to use the casting logic in the constructor?</p>
  
  <p><strong>lib/Price.pm6</strong></p>
  
  <pre><code>#!/usr/bin/env perl6 -w
  
  use v6;
  
  unit class Price:ver&lt;0.0.1&gt;;
  
  class X::Price::PriceInvalid is Exception {
      has $.price;
  
      method message() {
          return "Price $!price not valid"
      }
  }
  
  # Price is stored in cents USD
  has $.price;
  
  multi method new(Int $price) {
      say "Int constructor";
      return self.bless(:$price);
  }
  
  multi method new(Num $price) {
      say "Num constructor";
      return self.new(Int($price * 100));
  }
  
  multi method new(Str $price) {
      say "String constructor";
      $price .= trans(/&lt;-[0..9.]&gt;/ =&gt; '');
      unless ($price ~~ m/\.\d**2$/) {
          die(X::Price::PriceInvalid(:$price));
      }
      return self.new(Num($price));
  }
  
  submethod BUILD(:$!price) { say "Low-level BUILD constructor" }
  
  method toString() {
      return sprintf("%.2f", ($!price/100));
  }
  </code></pre>
  
  <p><strong>t/price.t</strong></p>
  
  <pre><code>#!/usr/bin/env perl6 -w
  
  use v6;
  use Test;
  
  use-ok 'Price', 'Module loads';
  use Price;
  
  # test constructor with Int
  my Int $priceInt = 12345;
  my $priceIntObj = Price.new(price =&gt; $priceInt);
  is $priceIntObj.toString(), '123.45',
      'Price from Int serializes correctly';
  
  # test constructor with Num
  my $priceNum = Num.new(123.45);
  my $priceNumObj = Price.new(price =&gt; $priceNum);
  is $priceNumObj.toString(), '123.45',
      'Price from Num serializes correctly';
  
  # test constructor with Num (w/ extra precision)
  my $priceNumExtra = 123.4567890;
  my $priceNumExtraObj = Price.new(price =&gt; $priceNumExtra);
  is $priceNumExtraObj.toString(), '123.45',
      'Price from Num with extra precision serializes correctly';
  
  # test constructor with Str
  my $priceStr = '$123.4567890';
  my $priceStrObj = Price.new(price =&gt; $priceStr);
  is $priceStrObj.toString(), '123.45',
      'Price from Str serializes correctly';
  
  # test constructor with invalid Str that doesn't parse
  my $priceStrInvalid = 'monkey';
  throws-like { my $priceStrInvalidObj = Price.new(price =&gt; $priceStrInvalid) }, X::Price::PriceInvalid,
      'Invalid string does not parse';
  
  done-testing;
  </code></pre>
  
  <p><strong>Output of <code>PERL6LIB=lib/ perl6 t/price.t</code></strong></p>
  
  <pre><code>ok 1 - Module loads
  Low-level BUILD constructor
  ok 2 - Price from Int serializes correctly
  Low-level BUILD constructor
  not ok 3 - Price from Num serializes correctly
  # Failed test 'Price from Num serializes correctly'
  # at t/price.t line 18
  # expected: '123.45'
  #      got: '1.23'
  Low-level BUILD constructor
  not ok 4 - Price from Num with extra precision serializes correctly
  # Failed test 'Price from Num with extra precision serializes correctly'
  # at t/price.t line 24
  # expected: '123.45'
  #      got: '1.23'
  Low-level BUILD constructor
  Cannot convert string to number: base-10 number must begin with valid digits or '.' in '⏏\$123.4567890' (indicated by ⏏)
    in method toString at lib/Price.pm6 (Price) line 39
    in block &lt;unit&gt; at t/price.t line 30
  </code></pre>