John M. Dlugosz wrote:
What does this mean?

our sub outer ()
   our sub inner () { ... }

inner;  # defined?

No, because {...} is just a declaration. You can give a
definition later in the surrounding module/package/class.
Within that scope there can be only one definition, of course.

The above just is the same as

   sub outer () {...}
   sub inner () {...}

unless of course a sub special form also creates an 'our' scope.
Well, or I don't understand what 'our' means.

I think this should be illegal. Nested named subs makes sense for 'my', with the rules of visibility matching the ability to clone the closure. But putting the nested sub into package scope is nonsense. It's really a different clone every time outer is called, and doesn't make sense to call unless outer is already pending.

Sorry, I have the impression you mix up the definition of the
inner sub and the creation of invocations of it. Why should an
invocation of outer also invoke inner? Or why should that cause
a re-definition at runtime or some such.

If inner doesn't actually need anything from outer's block scope, then there is no reason to declare it nested. If you have something specific in mind, like creating specific clones on the fly, then the code in outer can explicitly post the version it creates to the package scope and make it clear exactly when it's being created.

If I understand that correctly, then it's orthogonal to the issue
of scoping. Yet in other words, writing the definition of inner into
outer is a matter of taste, like e.g. indentation style.

our sub outer (::T $x)
   # explicitly create a new multi with every specialization
   state %didit;
   unless ++ %didit{ $x.HOW } {
      my multi sub inner (T $x)  {  ... }
      Package::<&inner> = &inner;

Why should a programmer do a compiler's task? Note that the last line
simply overwrites the previous binding of the symbol unless multis
have special assignment semantics. So I think it should read

    &OUR::inner:(T) = &inner;

I always thought that a generic sub is about sharing a single
body between several types. The above seems to require different
bodies for different bindings of ::T. That is the task of a multi
sub. Now if you can write a type function that computes the
implementations from the input types then you can eagerly call
that at compile time or lazily at runtime. In the latter case you
can cache the implementations if you like. But you can also forget
them as needed because they can be re-computed. Thus dispatch is
just an implementation strategy to fit the abstract concept onto
a concrete, finite machine.

Regards, TSa.

"The unavoidable price of reliability is simplicity" -- C.A.R. Hoare
"Simplicity does not precede complexity, but follows it." -- A.J. Perlis
1 + 2 + 3 + 4 + ... = -1/12  -- Srinivasa Ramanujan

Reply via email to