Clone Wars

Apologies to those that have OO steeped in their blood. I am a wary traveller in OO space,  maybe I am an technician, not an architect at heart. So for me, no sweeping frameworks unless and until they are needed. And, frankly, one can go a long way on procedural code with subroutines to gather repetitive code sequences.

(And don’t get me started on functional programming…)

Some time ago, I was tasked to write a LIMS in old perl. Physical ‘aliquots’ with injections of various liquids would be combined and recombined by bio-machines. This led to a dawning realization that these aliquot objects could be modelled in an object style with parent / child relationships. After a few weeks, I proudly delivered my lowly attempt at ‘Mu’ for this (and only this) problem. Kudos to the P6 team – after a couple of weeks in here, it’s just sensational the level of OO power that the real Mu delivers:

Screenshot 2017-09-20 19.32.21

Now, hard at work, on the perl6 version of Physics::Unit, I am wondering how to put the OO theory into productive practice. One of my aims was to find a medium sized (not core tools) problem that (i) I know something about and (ii) would be a good-sized problem to wrangle.

So I am enjoying the chance to design some classes and some interfaces that will make this all hang together. But – as an explorer, it has become clear that I only have three options. The problem runs like this:

  • There is a parent Measure class that contains the methods for any real-world measurement handling dimension, units, value and errors.
  • Then there are child classes for my Distance $d = ’42 m’, my Time $t = 3 s’, etc.
  • First level, I have an operation like … my $r = ’23 ft’ + $d;

Initially I had some success with object types ::T – but these only let you read the type and  duplicate if needed for a new left hand side container. Then I tried the built in (shallow) clone method. But…

  • What about the operation … my $s = $d / $t?
  • How do I create a new Speed object programatically?

Ultimately, thanks to rosettacode.org, I worked out that $x.perl.EVAL with some ~~ s/// substitions on the way would do the trick!

Phew. Please comment below if you have a better way to share – or would like to point out the risks of this technique…

Advertisement

11 Comments

  1. scimon says:

    So I’m on the train at the moment so can’t easily check the docs but I am pretty sure you can make a new multi infix \ operator that matches a Distance on the left and Time on the right and returns a Speed.

    When I get into the office and there are less tunnels I shall try and find some more helpful detail.

    Like

    1. p6steve says:

      Thanks Simon – that would be much appreciated. I am using an infix to do “Measure Maths” – such as Speed = Distance / Time to handle units and errors. When it comes to the types, these all inherit from a general Measure type. I need to generate a new child at runtime from a string – e.g. my Str $s = ‘Speed’; my ::T = $s; my ::T .=new (value => 42, units => m/s); My understanding of perl6 type variables is that I can load ::T from the infix or method signature if I have that type passed in, but I cannot interpolate a string into it to dynamically set the child Type.

      Like

  2. gfldex says:

    In Perl 6 types are objects. To create an instance at runtime you need a type literal or a variable that hold the type. To get a type object form a name of a type at runtime, use the ::() dynamic lookup operator.

    my $type = ‘Int’;
    my $type-object = ::($type);
    my $instance = $type-object.new(10);
    dd $instance;
    #OUTPUT: «Int $instance = 10␤»

    Like

    1. p6steve says:

      That’s the ticket – thanks!

      Like

  3. scimon says:

    So here’s a very quick version of my idea. We define a Unit role and then differnt unit types. Then we can add a new infix / that is a Speed constructor.

    —-

    module SI {

    role Unit {
    has Numeric $.size;
    has Str $.descriptor;

    method Str(–> Str) {
    return “{$.size}{$.descriptor}”;
    }

    method Rat(–> Rat) {
    return $.size.Rat();
    }
    }

    class Distance does SI::Unit {
    submethod BUILD( Numeric :$size ) {
    $!size = $size;
    $!descriptor = ‘m’;
    }
    }

    class Time does SI::Unit {
    submethod BUILD( Numeric :$size ) {
    $!size = $size;
    $!descriptor = ‘s’;
    }
    }

    class Speed does SI::Unit {
    submethod BUILD( Numeric :$size ) {
    $!size = $size;
    $!descriptor = ‘m/s’;
    }
    }

    multi infix:( SI::Distance $d, SI::Time $t –> SI::Speed ) is export {
    return SI::Speed.new( size => $d.size / $t.size );
    }

    }

    Like

  4. gfldex says:

    One could improve https://gist.github.com/5ff7b47eb10ebeff0c4913e38259918b by having a proper regexp to take the unit part of the matcher from %suffix-to-type. Also a slang would be better for literals then loads of operators. (Re-)Defining operators is still really slow in Rakudo.

    But not me, because I need to rush to work!

    Like

    1. p6steve says:

      Nice work! Wish I could be that fast!

      Like

    2. p6steve says:

      I think the amount of user variation expected on inputs – everything from miles per hour through m/sec^2 could use a Grammar. Gives me a chance to try that too! Since only +-*/ make sense I have been planning to overload these in a visible way… need to think about a slang.

      Like

  5. scimon says:

    sub postfix:( Numeric $size –> SI::Distance ) is export {
    return SI::Distance.new( size => $size );
    }

    Lets you do :

    my $d = 10m;

    Which is nice too.

    Like

    1. p6steve says:

      Thanks scimon – I think that this combined with the ability to dynamically pick the type from a string with ::($type-name) is ideal…

      Like

Leave a Comment

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s