Categories
Posts in this category
- Current State of Exceptions in Rakudo and Perl 6
- Meet DBIish, a Perl 6 Database Interface
- Perl 6 Hackathon in Oslo: Be Prepared!
- Perl 6 Hackathon in Oslo: Report From The First Day
- Perl 6 Hackathon in Oslo: Report From The Second Day
- Rakudo Hack: Dynamic Export Lists
- SQLite support for DBIish
- Upcoming Perl 6 Hackathon in Oslo, Norway
- A shiny perl6.org site
- Creating an entry point for newcomers
- An offer for software developers: free IRC logging
- Sprixel, a 6 compiler powered by JavaScript
- Announcing try.rakudo.org, an interactive Perl 6 shell in your browser
- Another perl6.org iteration
- Blackjack and Perl 6
- Why I commit Crud to the Perl 6 Test Suite
- This Week's Contribution to Perl 6 Week 5: Implement Str.trans
- This Week's Contribution to Perl 6
- This Week's Contribution to Perl 6 Week 8: Implement $*ARGFILES for Rakudo
- This Week's Contribution to Perl 6 Week 6: Improve Book markup
- This Week's Contribution to Perl 6 Week 2: Fix up a test
- This Week's Contribution to Perl 6 Week 9: Implement Hash.pick for Rakudo
- This Week's Contribution to Perl 6 Week 11: Improve an error message for Hyper Operators
- This Week's Contribution to Perl 6 - Lottery Intermission
- This Week's Contribution to Perl 6 Week 3: Write supporting code for the MAIN sub
- This Week's Contribution to Perl 6 Week 1: A website for proto
- This Week's Contribution to Perl 6 Week 4: Implement :samecase for .subst
- This Week's Contribution to Perl 6 Week 10: Implement samespace for Rakudo
- This Week's Contribution to Perl 6 Week 7: Implement try.rakudo.org
- What is the "Cool" class in Perl 6?
- Report from the Perl 6 Hackathon in Copenhagen
- Custom operators in Rakudo
- A Perl 6 Date Module
- Defined Behaviour with Undefined Values
- Dissecting the "Starry obfu"
- The case for distributed version control systems
- Perl 6: Failing Softly with Unthrown Exceptions
- Perl 6 Compiler Feature Matrix
- The first Perl 6 module on CPAN
- A Foray into Perl 5 land
- Gabor: Keep going
- First Grant Report: Structured Error Messages
- Second Grant Report: Structured Error Messages
- Third Grant Report: Structured Error Messages
- Fourth Grant Report: Structured Error Messages
- Google Summer of Code Mentor Recap
- How core is core?
- How fast is Rakudo's "nom" branch?
- Building a Huffman Tree With Rakudo
- Immutable Sigils and Context
- Is Perl 6 really Perl?
- Mini-Challenge: Write Your Prisoner's Dilemma Strategy
- List.classify
- Longest Palindrome by Regex
- Perl 6: Lost in Wonderland
- Lots of momentum in the Perl 6 community
- Monetize Perl 6?
- Musing and the future of feather and the Pugs repository
- Musings on Rakudo's spectest chart
- My first executable from Perl 6
- My first YAPC - YAPC::EU 2010 in Pisa
- Trying to implement new operators - failed
- Programming Languages Are Not Zero Sum
- Perl 6 notes from February 2011
- Notes from the YAPC::EU 2010 Rakudo hackathon
- Let's build an object
- Perl 6 is optimized for fun
- How to get a parse tree for a Perl 6 Program
- Pascal's Triangle in Perl 6
- Perl 6 in 2009
- Perl 6 in 2010
- Perl 6 in 2011 - A Retrospection
- Perl 6 ticket life cycle
- The Perl Survey and Perl 6
- The Perl 6 Advent Calendar
- Perl 6 Questions on Perlmonks
- Physical modeling with Math::Model and Perl 6
- How to Plot a Segment of a Circle with SVG
- Results from the Prisoner's Dilemma Challenge
- Protected Attributes Make No Sense
- Publicity for Perl 6
- PVC - Perl 6 Vocabulary Coach
- Fixing Rakudo Memory Leaks
- Rakudo architectural overview
- Rakudo Rocks
- Rakudo "star" announced
- My personal "I want a PONIE" wish list for Rakudo Star
- Rakudo's rough edges
- Rats and other pets
- The Real World Strikes Back - or why you shouldn't forbid stuff just because you think it's wrong
- Releasing Rakudo made easy
- Set Phasers to Stun!
- Starry Perl 6 obfu
- Recent Perl 6 Developments August 2008
- The State of Regex Modifiers in Rakudo
- Strings and Buffers
- Subroutines vs. Methods - Differences and Commonalities
- A SVG plotting adventure
- A Syntax Highlighter for Perl 6
- Test Suite Reorganization: How to move tests
- The Happiness of Design Convergence
- Thoughts on masak's Perl 6 Coding Contest
- The Three-Fold Function of the Smart Match Operator
- Perl 6 Tidings from September and October 2008
- Perl 6 Tidings for November 2008
- Perl 6 Tidings from December 2008
- Perl 6 Tidings from January 2009
- Perl 6 Tidings from February 2009
- Perl 6 Tidings from March 2009
- Perl 6 Tidings from April 2009
- Perl 6 Tidings from May 2009
- Perl 6 Tidings from May 2009 (second iteration)
- Perl 6 Tidings from June 2009
- Perl 6 Tidings from August 2009
- Perl 6 Tidings from October 2009
- Timeline for a syntax change in Perl 6
- Visualizing match trees
- Want to write shiny SVG graphics with Perl 6? Port Scruffy!
- We write a Perl 6 book for you
- When we reach 100% we did something wrong
- Where Rakudo Lives Now
- Why Rakudo needs NQP
- Why was the Perl 6 Advent Calendar such a Success?
- What you can write in Perl 6 today
- Why you don't need the Y combinator in Perl 6
- You are good enough!
Wed, 17 Nov 2010
The Real World Strikes Back - or why you shouldn't forbid stuff just because you think it's wrong
Permanent link
tl;dr;; version: arbitrary API limitations do more harm than good, even if meant well in the first place.
Most advanced libraries that help you with date calculations have separate data types for a point in time, and a time span. That's because those two concepts actually have different semantics. It doesn't make sense to add two points in time, but it does make sense to add two durations, or add a duration to a point in time.
In Perl 6, those two types are called
Instant and
Duration. And obviously it makes sense to multiply a Duration
with a number, but it doesn't make sense to multiply two Durations, or take a
power of a Duration. Right?
That's the opinion that both the Perl 6 specification and the implementation in Rakudo reflected. Until recently, when somebody started to actually use it.
That's when the real world struck back. Carl Mäsak did some timings, and then calculated averages and standard deviations. And for calculating standard deviations, you actually have to square those durations, add them up, and then calculate the square root.
So this perfectly legitimate use case shows that multiplication (and also
exponentiation) are perfectly fine operations on Durations. Likewise the
current specification disallows division of two Durations. Why? It's perfectly
fine to ask for the ratio of two time spans. How much longer (or shorter) are
my meetings with my current boss, compared to those with my previous boss?
That's the question that Duration / Duration answers.
So, the real world taught me that putting restrictions on the allowed operations is a bad idea. It was meant well, it was supposed to catch operations that don't made sense to the designer, and presumably would catch some error that a confused beginner might make. But in the end it did more harm than good.
Currently the Duration class stores a number, and
re-dispatches all operations to that number, forbidding some of them. Having
learned my lesson, I suggest we get rid of it, and have Instant -
Instant return that number straight away. If some day we want to
add functionality to Duration, we can still create that class as
a subclass of the number.
Comments / Trackbacks:
Trackback URL:
/blog-en/perl-6/real-world-strikes-back.trackback
Steve wrote
Hi.
I'm guessing that a duration object would cover a period of time between two instants - perhaps 7.75 hours - 120 seconds - three years - could all of these be considered durations?
If this is the case, It would appear to me that the solution Mäsak required wasn't to multiply two durations.
The real required is subtle - but different.
I would have thought that for the calculation, the magnitude of the duration would be required rather than just an arbitary period - the magnitude would vary for durations - and what is relevant for some purposes ( a nice round number like seconds ) may not be the same as for others.
I'm not sure the assumption is usefull for either advanced programmers or novices - I would encourage a novice to think, to have a small boundry to help orientate their mind to the problem space - it could be argued that a duration.seconds / duration.seconds ( as an example ) helps - it makes the loss of information explicit.
The final comment seems to define some of my fears -
If some day we want to add functionality to Duration, we
can still create that class as a subclass of the number.
Rather than regarding Duration as an entity in its own right, to be expanded and enriched, this remark seems to tie it forever to an underlying numeric implementation. I suspect this leaves the proposal open to an accusation of being a practice I've heard called "primitive obsession"?
dankuck wrote
It seems safe to start allowing it. Since legacy code doesn't yet use the disallowed operations, it will still run correctly. The only code that is in danger is code that depends on exceptions being thrown. That seems limited to test suites and methods that use disallowed operations for "type checking".
It's still frustrating though. You're right that it would've been less trouble to just allow these operations since they were technically possible.
Steve wrote
Having read S02
http://perlcabal.org/syn/S02.html
I'm not to sure of the benefit of a duration class as specified - and understand more of the frustrations - I consider Duration to be useful as a class level similar to Calendar objects - but the form suggested seems to be too low level ( in my narrow field of application programming experience ) to be of much use to me?
Songmaster wrote
Units are important
I agree with Steve, the units of the duration usually matter, so the user should be required to state whether they want the number they get back to be expressed in seconds, hours, days or years etc. Of course that opens the question as to whether they want just 123.45 seconds, or if they want to display the same duration as 2 minutes, 3 seconds, 450 milliseconds. That's an API issue, but I can see uses for both.
Eevee wrote
This is totally crazy to me. Squaring a duration is fine if you're going to actually preserve the units and have a whole unit system in the stdlib, but otherwise, you're pretending a physical quantity is just a number. If you want to square the number of seconds, you should ask for the number of seconds, not expect an object to act like one. Encapsulation and all that.
What's the square of an hour? 1? 3600? 12960000? 12960000000000? Please don't build this silly ambiguity into such a core part of the language. Perl 5's DateTime is ornery for good reason.
Dividing two durations makes perfect sense, of course; the units merely cancel.
Keith Thompson wrote
Then why not just use numbers?
If all numeric operations on Durations are going to be allowed, then why not just use numbers in the first place? What does making Duration a separate type buy you?
I suggest that squaring a Duration is a sufficiently unusual thing to do that it deserves to be made explicit. Presumably you can explicitly convert a Duration to its numeric value. (I like the "duration.seconds" syntax Steve mentioned; is that already there?) So do that: convert each Duration to a number, square the numbers, add them, take the square root, and convert the result back to Duration. And let the compiler warn you if you multiple two durations *unintentionally*.
(Either that or support more general units, so the square of a Duration is a number of square seconds.)
hobbs wrote
One more word of agreement with Steve and Eevee -- squaring or multiplying durations is *wrong* and broken unless you have a class that can represent units of Duration^2.
Example: (2 hours)^2 = 4 (hours^2). (120 minutes)^2 = 14400 (minutes^2). *If* you can store those values with their correct units, they're usable. But if you make the mistake of doing operations on the underlying numbers while leaving the units the same, giving 4 hours and 14400 minutes respectively, then what happens if you try to add them? 14400 minutes converts to *240 hours*, which is a completely useless quantity, giving a sum of 244 hours. Divide that by two to get 122 hours and take the square root (making again the same mistake with the units) and you get a bit over 11 hours. Congratulations, you just figured out that the RMS of 2 hours and 2 hours is 11 hours!
Now finally... there should be a Duration class. It should *not* represent a single number in any unit, but instead be a compound type like a DateTime::Duration in Perl 5. This is because the ideas of, e.g. "Add 1 day" and "Add 24 hours" aren't identical -- they differ across e.g. a DST change event. And such a Duration *shouldn't* support operations such as squaring or multiplication with another Duration because they're meaningless, but it *should* be able to produce a Numeric value representing its magnitude in some unit, and that number can be manipulated all you want.
Moritz wrote
Units
I don't understand all your horrors about units and squaring durations. The spec explicitly says that using a Duration as a number returns the value in seconds.
So things like (2 hours)**2 are well defined.
Perl 6 doesn't have a system for storing arbitrary units. Duration is the only type that we know the unit of. Now there are three possible solutions
1) disallow some operations that do make sense, just because we can
2) assume a default unit
3) implement a complete unit system
1) doesn't reallly makes sense, as I argued at length in the blog post. 3) is really outside the scope of a general purpose programming language. It's a nice addition as a user-space module (and Perl 6 is flexible enough to allow that), but adding it just bloats the language.
A final remark: Durations really store distances between points in time, not points in a calendar. They don't care about time zones, leap seconds or daylight saving time. They *can* be represented as seconds. And since that's the simplest solution, I don't see why they shouldn't.
Klausens wrote
I think the question is how many chars you save on the one hand and support bugs on the other hand.
In Perl6 it should be easy to force a numeric context for your Duration, so you can calculate with it. re-convert it to a Duration also should be not the problem.
If you regard this example as a special case, a manageable expense.
My fear is, that like in Perl5 (too?) many things are possible somehow, but if you want to work earnest you need:
use strict; use warnings; ... and then things become unhandy.
I still found no easy way to say a "eq" that its ok that a value is undef or undef equals undef. If Perl5 was designed from scratch to be stricter maybe there would be a nicer way.
hobbs wrote
A "Duration" that represents a number of seconds is a fundamentally useless type and should be replaced with Num -- or upgraded to be actually useful. :)
Steve wrote
Behavour not Units
"I don't understand all your horrors about units"
Firstly - I agree with the thrist of your article, and concur with the conclusion that "Having learned my lesson, I suggest we get rid of it, and have Instant - Instant return that number straight away"
However - the units thing scares me.
Any concern I have over units isn't about units - its about the risk of creation of Anemic Classes - http://www.martinfowler.com/bliki/AnemicDomainModel.html
The emphasis on units seems to present the assumption that the important part of representing certain concepts is with some arbitary label, rather than the underlying behavour which would be found in a class - Which to me seems to encourage bad design and sloppy programming.
As an example - in the field of "money" - a common concept in programming.
To share $3.55 4 ways is more difficult that just ( $3.55 / 4 ) - you might want three times 89 cents, and once times 88 cents.
For me, that deserves to be encapsulated, so as to keep code free of cruft, and ensure that we aren't accidentally manufacturing money.
Allowing arbitary types provides false confidence, and promotes sloppy programming - if its important enough to have a unit it often warrents its own class.
Write a comment
The comments on this blog post have been disabled; the comment form below will not work.