Austin Hastings wrote:
I think of this as very much like the typed-undef we discussed last
month or so: ... should return an unthrown exception wrapped in
undef-ness.


The type returned by ... should just have a multitude of type-casting
tricks associated:

my int $i = ...; # Fails at compile time -- no good conversion.

my Int $i = ...; # Warns at compile time, fails at runtime.

I don't get the reasoning here. If Yada Yada Yada is to indicate code that you haven't written yet, it should never fail at compile time unless it's impossible to compile the program without knowing what that code is, so


my int $i = ...;

should compile. The problem would arise when you actually tried to run that particular bit of code, which may well look to Parrot like 'die horribly'.

If Yada Yada Yada is not to indicate code that you haven't written yet, then what is it really for?

I would guess again that the body of the sub not being actually
executed until the sub is called means that C<...> passes through the compile phase without a problem. The compiler would have to
special-case it though, to allow the redefinition.


Perhaps not. If {...} evaluates to C<(Code)(undef but something)>, the
transition from C<defined(&foo) == FALSE> to C<defined(&foo) == TRUE>
might not be grounds for a redef warning.

That would make sense... if ... gave you an indefined code block (rather than code which returns an undefined value, which we all know and love, or at least I love it), it would actually make a LOT of sense.


I'm going to assume that if you tried

my Int $number = ...;
$number = 5;

it would still die at run time on the first C<...>. I really hope it would anyway, because if you really want to do something like that
we've already got C<undef>.


This is wrong. The purpose of C<undef> is "I declare that I've thought
about the issue and at this point in the code $number should have no
value." The purpose of C<...> is "I declare that there should be
something here, but I haven't thought about it yet."

IOW, C<...> is a form of literate programming that's relatively
self-explanatory and highly compatible with Agile development:

class foo {
has $.x = ...;
method bar() {...}
method baz($a)
{
if ($a) {
.bar();
}
say "Hello";
}
}


class foo_test
{
  is UnitTestCase;
  has $.foo;

  method test_empty_baz()
  {
     $.foo = new foo;
     $.foo.baz(undef);
  }
}

This code should work okay -- no Yadda ever gets executed.

Then when I add:

  method test_valid_baz()
  {
    $.foo = new foo;
    $.foo.baz(1);
  }

there should be a failure, because $.foo.baz calls $.foo.bar, which is
defined C<{...}>, which evaluates to an unspecified value exception.

Yes, that's more or less as I would expect it to work.


I thought class closures 'ran' at object creation time. I'm probably wrong about that. Object creation time would be a good time for that particular yada yada yada to start complaining though. I suspect
C<...> is going to be considerably more sophisticated than a macro
that replaces it with C<{ die }>.


I think the metaclass "class assembler" function will behave like this:

If only a Yadda is provided, just return a typed Yadda object.

If anything other than a Yadda:

If you provide a definition of any name, it goes in.

If you provide a Yadda, it gets recorded.

When wrapping up, if any methods are provided, then a special
yadda-on-not-found dispatcher is provided. If no methods are provided, a special yadda-on-not-inherited dispatcher is provided.


A similar data member access is provided.

So that:

  class Foo {
    has $.a;
    has $.b;
    ...
  }

Becomes:

  class Foo {
    AUTOMETH {
      if inherited($method_name), run it.
      else return sub {...};
    }

has $.a;
has $.b; AUTOMEMBER {
if inherited($member_name), return it.
else return \...;
}
}

So you can have objects made from class Foo, but if you try and get at a method which doesn't exist you get Yada instead of 'that method doesn't exist'... that makes sense, I think, because you can use any method names you like in your code, and the effect is basically 'this method hasn't been written yet'.


I would expect that to run and complain at compile time. That might
be irritating, but I'm not sure how else it could be done, because BEGIN blocks are run then, and when they're run you need to know what
values you're going to assign to the variables.


Unless you gather it up inside some sort of lazy evaluation construct
that keeps delaying the evaluation of it until you hit run phase, at which point you've probably got the entire BEGIN block ready to go,
with everything that comes after it also hanging around, and... no,
doesn't sound good does it?


Again, I like it. A partially defined object isn't fatal unless you
actually need that part.

If Yada is actually a value with a special type as you've said here, then it falls out quite well. You can put it into anything you like, you just get a problem the moment you try and take it out again and look at it, where the fact that it doesn't actually represent anything yet begins to be problematic. It's a nice variant on undef for use at development time.


Might be nice to have a small checker that you can use on production code to make sure you didn't leave any Yadas in it though :-)



Reply via email to