DBIish icon indicating copy to clipboard operation
DBIish copied to clipboard

X::AdHoc: Cannot look up attributes in a VMNull type object. Did you forget a '.new'?

Open demanuel opened this issue 2 months ago • 6 comments

I'm getting this written to std error:

Some exceptions were thrown in END blocks:
  X::AdHoc: Cannot look up attributes in a VMNull type object. Did you forget a '.new'?
      in code  at /home/demanuel/Projectos/Raku/App-Feeds/lib/App/Feeds.rakumod (App::Feeds) line 188
      in any <main> at /usr/share/perl6/runtime/perl6.moarvm line 1
      in any <entry> at /usr/share/perl6/runtime/perl6.moarvm line 1

Image:

imagem

demanuel avatar Apr 09 '24 20:04 demanuel

@demanuel - Are you sure the object you are making the call from has been instantiated? Was a .new called against it before the attempt to use DBIish?

More code would be a big help, here.

Xliff avatar Apr 10 '24 00:04 Xliff

@xliff i don't understand the questions.

It's failing when it's trying to create a new database handler. There's no .new call to be made.

demanuel avatar Apr 10 '24 10:04 demanuel

@demanuel

I'll get to the error message in your issue's title below.

But first, The full error message begins:

Some exceptions were thrown in END blocks:

Quoting the END phaser doc:

Runs after compilation during main execution, as late as possible, only runs once. It will close any open handles automatically.

When phasers are in different modules, the INIT and END phasers are treated as if declared at use time in the using module. (It is erroneous to depend on this order if the module is used more than once, however, since the phasers are only installed the first time they're noticed.)

Is line 188 itself inside an END block?:

  • YES. If so, are you sure DBIish functionality remains available at that late stage? ("Runs ... as late as possible" means it runs at the end of the program, as it shuts down after the usual main code has completed, normally or abnormally.)

  • NO. If not, then I presume some prior exception has been thrown while processing line 188, and not handled, and then that has led to the program being shut down (and then the attempt to shut down has itself also gone wrong?), ultimately leading to the error message misleadingly reporting line 188 as a problem appearing in an END block.

As a separate matter, if there is an END block in more than one module in your program (and/or in a single module that gets used twice or more in your program), then do those END blocks (or does that END block) work correctly according to the semantics described by the above quoted doc?


The second part of your error message, as quoted in your issue's title, was:

Cannot look up attributes in a VMNull type object. Did you forget a '.new'?

The "VMNull type object" is a type object, and not only that, but a "Null", and not only that, but a "VM" null. Any one of those extremely strongly suggests a failure to initialize an object. Given it's all of those things at once, it's pretty much guaranteed that the problem is a failure to initialize an object at a very basic level.

And the line it points to is line 188. You've made it impossible to cut/paste that line, but it's the DBIish.connect one.

It's failing when it's trying to create a new database handler. There's no .new call to be made.

A new database handler will be a new object. Most new objects are created by calling .new. Some are indirectly created by calling some other routine, eg .connect, which in turn calls .new. Please interpret any mention of .new in a Raku error message, or doc, or comment written by a Rakoon, as meaning create a new object.


In summary, your program is failing during processing of line 188, which involves creation of a new database handler, and the failure is very basic, with a failure even to create a new object of some kind at the VM level, and it's occurring during an attempt to shut down the program that was either in progress before arriving at line 188 (because line 188 is inside an END block) or was triggered by the attempt to process line 188.


Hopefully the above leads somewhere useful.

Either way, there are two main options for making further progress in this issue:

  1. Option 1 is that you provide code that we can cut and paste and run and see the same error message. If you do that, then it generally becomes relatively easy to help, even if it takes a bunch of to and fro messages. Even better, the amount you and we and readers learns along the way is maximized, in addition to the benefit to you of maximizing the chances we get to a solution, and do so relatively quickly.

  2. Option 2 is that you don't provide code that we can cut and paste and run and see the same error message. If you don't, then it generally becomes relatively difficult to help, and for you to reply, and we are likely to have to write a much greater number of much more complicated to and fro messages, with everyone learning much less along the way, and the energy and time spent trying to get to an answer being much greater, which is a very bad thing for a range of reasons.

Choosing option 2 means you are choosing to make everyone's life, including yours, difficult, both now, as we try to make progress, and for years or decades to come, whenever people read this issue. That said, it is of course your decision which way we go, and I hope I will have the patience to continue to try help no matter what you decide.

raiph avatar Apr 10 '24 16:04 raiph

Is line 188 itself inside an END block?:

No. I removed all the end blocks from my code (not libs) and i still got the message. It doesn't make sense, IMO. :-(

And the line it points to is line 188. You've made it impossible to cut/paste that line, but it's the DBIish.connect one.

I just pasted an image, to show that the error in the line 188 it only contains the DBIIsh.connect.

Unfortunately i wasn't able to create a small reproducible case. So my only option is to provide my real bad code (i'm a newbie - and it's not even finished) and instructions to run it.

I will think a way of providing the code and instructions.

demanuel avatar Apr 10 '24 21:04 demanuel

Code attached to this comment: bug.tar.gz. Please note that the file is 8.7MiB and contains a sqlite database with 36MiB when uncompressed. (Probably most of the entries in the articles table can be deleted)

Inside the folder there is a readme and there is a runme.sh. Just set the env XDG_DATA_HOME and run the runme.sh script, then press 'q'.

Make sure that you have the required deps:

use Term::termios;
use File::Temp;
use Terminal::LineEditor;
use Terminal::LineEditor::Raw
use DBIish;
use DBDish::SQLite::Connection;
use LibXML;
use LibXML::Document;
use Cro::HTTP::Client;
use Data::Dump::Tree;
use HTML::EscapeUtils;
use Math::Combinatorics <variations>;
use DateTime::Grammar;
use JSON::Fast;
use Log::Async;

Please forgive the crappy code,

demanuel avatar Apr 10 '24 22:04 demanuel

If you reduce Feeds.rakumod down to this:

unit class App::Feeds;
method !calculate-new-articles-similarity() {
    my $query = qq:to/END/;
        with
            select t.article_id from article_tags;
        END
    END
    my @articles = self!select-query($query);
}
method !select-query($query, *@values --> List) { List }

and run it with:

raku -Ilib -e 'use App::Feeds;'

You still get the error:

Some exceptions were thrown in END blocks:
  X::TypeCheck::Binding::Parameter: Type check failed in binding to parameter '<anon>'; expected App::Feeds but got Mu (Mu)
      in method select-query at /Users/bruce/Raku_email_bug_DBIish/bug/lib/App/Feeds.rakumod (App::Feeds) line 13
      in code  at /Users/bruce/Raku_email_bug_DBIish/bug/lib/App/Feeds.rakumod (App::Feeds) line 10
      in any <main> at /opt/homebrew/Cellar/rakudo-star/2024.03/bin/../share/perl6/runtime/perl6.moarvm line 1
      in any <entry> at /opt/homebrew/Cellar/rakudo-star/2024.03/bin/../share/perl6/runtime/perl6.moarvm line 1

The problem is that you have doubled ENDs, maybe from copy-and-paste, or some previous SQL construct like "BEGIN"..."END". The first "END" is terminating the $query string, and the second "END" is starting an END phaser. See https://docs.raku.org/language/phasers . Removing the first END in calculate-new-articles-similarity resolves the issue.

To avoid this problem in my own future, I plan to discontinue all use of "END" as qq::to/END/ in my own code. More descriptive delimiters like /END_OF_SQL/ will be clearer, and never accidentally collide with the END phaser. We should probably do the same in the Raku docs.

In hindsight, the mention of END blocks in the error message should have clued me to at least search for "END" in your code, but that did not happen. I blame the gale-force winds outside my window.

As far as kindness goes, I declare that this code was challenging for me to reduce to a minimal example, so I understand why you could not do so. You did recognize the need to reduce it, you did try to reduce it, and you followed through with giving us the next-best-thing (runnable code). If you can also keep from being discouraged by the weight of having asked in the wrong place, you will we doing far better than the average help-seeker.

I encourage you to hone your skills at "reduce to a minimal example". Commenting/cutting your own code, finding you made it un-runnable, restoring the last part removed and trying a different bit to trim... it is a odd rhythm to learn, a skill-set that does not arise from coding, only from debugging. In sharpening that peculiar skill, you will not only get help more quickly and easily, you will frequently find you solve your own problem. It is like "rubber-ducking", but with more cursing. https://en.wikipedia.org/wiki/Rubber_duck_debugging .

-- Hope this helps, Bruce Gray (Util of PerlMonks)

Util avatar Apr 11 '24 02:04 Util

Now i feel stupid. I still don't understand how i could have done that stupid mistake.

@Util , I thought the error message i was for END {} phaser. I agree with all of your analysis.

My apologies.

EDIT: why would this error appear only on the exit of the script. Shouldn't appear when the function would be called? I think this is the reason i got to think that it was because of a END {} phaser. If the error would appear when the function was called, i think it would be easier for me to detect it.

demanuel avatar Apr 11 '24 08:04 demanuel

Hi @demanuel,

why would this error appear only on the exit of the script.

Because it only happened on the exit of the script.

Shouldn't appear when the function would be called?

Yes, it happened when the function was called.

I think this is the reason i got to think that it was because of a END {} phaser.

END phasers don't need the block, just the keyword END. Consider this code:

END say 'END';
say 42;

displays:

42
END

If the error would appear when the function was called, i think it would be easier for me to detect it.

It does appear when the function was called. It just wasn't getting called when you expected it, but instead as the script exited, because you had accidentally marked it as END code.

Hth!

raiph avatar Apr 13 '24 23:04 raiph

END phasers don't need the block, just the keyword END. Consider this code:

I didn't know that. That explains the issue! Thanks for the explanation! I'm now following the coding practice of not using END as a delimiter for the heredoc as suggested by @Util .

Many thanks!

demanuel avatar Apr 13 '24 23:04 demanuel

Just in case anyone finds this and is still not completely sure what is going on, it boils down to something like:

say q:to/END/;
   THIS IS NOT THE
   END
END
say "NEXT";
say "LAST";

Where the expectation is that it will output something like:

   THIS IS NOT THE
   END

NEXT
LAST

But instead it would output:

THIS IS NOT THE

LAST
NEXT

This is because the first END (which is intended to be some text in the heredoc,) is taken to be the heredoc terminator and the second END introduces a block-less END phasor with the following statement.

This category of infelicity is not limited to the use of END as the heredoc delimiter but could apply to any phasor (https://docs.raku.org/language/phasers) that might appear in the heredoc.

So there may be two things to bear in mind here:

  • Don't use a token that may appear in the heredoc as the heredoc delimiter
  • Don't use a raku keyword as the hereword

jonathanstowe avatar Apr 14 '24 08:04 jonathanstowe