top | item 20377195

(no title)

mclehman | 6 years ago

I don't necessarily want to wade into the discussion on the tone of the article, but I do want to detail something I've used Perl 6 for that makes me really enjoy working with the language. I've noticed a trend in threads where P6 comes up: I rarely see people actually point to specific instances where P6 features have been helpful. This lack of examples certainly doesn't help push back against the idea that the language isn't usable or, indeed, useful with anything less than 100% of the spec implemented.

I use P6 for all of my small deployment scripts (as well as a number of small utilities I've written, like a tmux wrapper). It gets out of my way when I just need something quick and useful from the start. For example it's exceedingly easy to wrap other utilities because arguments to MAIN generate a command line interface automatically.

It also provides features that help me as I move from a useful-but-dirty prototype to a more maintainable script or piece of a more complex system. Gradual typing is a big part of this. I tend not to add types for most things, but it's very easy to use the P6 type system to watch my back when I do want that help. It's not as good at catching things before runtime as a hardcore static type system, but it manages to warn me "... will never succeed with declared signature ..." often enough.

I have a no-frills, no-auth file sharing site I deploy periodically to get a web front-end to share things with people (usually already on a VPN, sometimes just on a LAN). At the moment, I use a simple deploy script to do this manually, but I'm considering setting something up to automatically deploy it when connecting to a particular network. I almost definitely won't get that part right on the first try and would really rather not end up accidentally deploying a no-auth filesystem on my server's public IP address.

Using the P6 type system, I can easily define a subset of IPv4 addresses:

    my @private-ranges = <10.0.0.0/8 172.16.0.0/12 192.168.0.0/16>;
    subset IPv4::Private of IPv4 where -> $ip { Net::Netmask.new(any @private-ranges).match($ip) };
Then simply defining MAIN with a typed (and named, in this case, hence the colon) argument will handle all the checking at the type level.

    sub MAIN(IPv4::Private :$ip) { ... }
Now I won't be able to deploy this service on a public IP as long as I use this deploy script as a primitive in whatever eventual solution I end up with, and the automatically generated usage message even helps communicate why a call failed (provided you have descriptive type/parameter names).

    λ |  ./deploy --ip=$(dig +short myip.opendns.com @resolver1.opendns.com) 
    Usage:
      ./deploy.p6 [--ip=<Private>]
    
    λ |  ./deploy --ip=10.0.0.2
    Deploy successful.

discuss

order

xisukar|6 years ago

Nice example about using the MAIN subroutine. I'd be interested on reading more about your uses of Perl 6 so should you blog about them, don't hesitate and share it with the P6 community.

mclehman|6 years ago

Thanks, I'll definitely keep it in mind.

MAIN is probably what I should point to as P6's killer feature for things of this scope. I tend to get sidetracked by math/functional features when I demo things even though stuff like this is a bit more practical and likely to get traction.

I just got around to cleaning up that tmux wrapper I mentioned above (https://gitlab.com/0xFORDCOMMA/sessions) and that might be worth writing something about. It's a miniscule project, but I think it highlights a lot of useful features.

One result of that clean-up that relates to this is the new usage output. It's still automatically generated [1], but adding purpose annotations to the multi-dispatch MAINs in `session` and using a P6 enum as a type constraint in the MAIN in `sessions` resulted in what I consider quite useful documentation pretty much for free.

    λ | -> session --usage
    Usage:
      session -- Create or enter default session 'misc/dev'.
      session <category> <session> -- Create or enter session '<category>/<session>'.
      session <session> -- Search all categories for matching session, switch to result if unique.

    λ | -> sessions --usage
    Usage:
      sessions [--style=<Style> (boxed compact)] -- Default display style is boxed.
The latter example is generated entirely from these two declarations:

    enum Style <boxed compact>;

    #|(Default display style is boxed.)
    sub MAIN(Style :$style = boxed) { ... }
[1] For anyone interested, you can have your cake and eat it too. Defining your own USAGE routine doesn't mean you have to give up the generated one. The generated output is available in the $*USAGE variable.

gbacon|6 years ago

Nice summary! I'd enjoy reading more of your success stories rather than more mindless hurr hurr! Perl bashing.

mclehman|6 years ago

Thanks! I'll see what I can do about writing things up and posting them somewhere. My site is a mess at the moment (always has been), but maybe this will motivate me to do something about that.