Beefy Boxes and Bandwidth Generously Provided by pair Networks
"be consistent"
 
PerlMonks  

Re: require in script breaks module

by haukex (Archbishop)
on Mar 02, 2019 at 16:58 UTC ( [id://1230763]=note: print w/replies, xml ) Need Help??


in reply to require in script breaks module

What's going on is that the sys/ioctl.ph file (at least the one on my system) defines a bunch of subs, however, it does not use something like Exporter to do so, it just defines them in whatever the current package happens to be. Also, require only loads a file once: if you have require 'sys/ioctl.ph' in your package main (i.e. test.pl) that gets called first, then the require 'sys/ioctl.ph' in package funnybusiness has no effect, and therefore, the sub funnybusiness::FIONREAD never gets defined.

There are several possible solutions, which one is most "elegant" depends... One possible solution might be to use do instead of require, because it always runs the file, no matter how many times it's been run before, but keeping in mind the error checking described in the documentation of do. Also, I'd move that do outside of the sub s1, there's no need for the file to get loaded every time the sub is called. As an alternative to do, one could do delete $INC{'sys/ioctl.ph'}; require 'sys/ioctl.ph'; to make sure the require loads the file (see %INC).

Yet another solution might be to do the following in one of the library files:

{ package Sys::Ioctl; BEGIN { delete $INC{'sys/ioctl.ph'}; require 'sys/ioctl.ph'; } }

And then to use Sys::Ioctl::FIONREAD() everywhere. This could also be separated out into its own Sys/Ioctl.pm file, which could in turn use Exporter to get those definitions exported in the usual manner. This is probably the solution I would favor in a larger application.

Replies are listed 'Best First'.
Re^2: require in script breaks module
by chrstphrchvz (Scribe) on Mar 04, 2019 at 08:13 UTC

    Thanks for the reply and suggesting possible workarounds.

    Peeking inside the .ph file on my machines, it's mostly just more requires. So unfortunately neither do 'sys/ioctl.ph' nor delete $INC{'sys/ioctl.ph'}; require 'sys/ioctl.ph' alone yield any improvement.

    I ended up moving the require to where it would be run once during the module's import, only nested in an eval so that any error is saved to a package variable. Then, when the feature requiring ioctl is used, any error will be croaked; and tests can check the package variable to know whether to skip. Here's the implementation: https://github.com/chrstphrchvz/perl-tcl-ptk/commit/75abce83f7

    Maybe there is something more elaborate that resists the effects of require appearing in "user" code, but because this particular feature in the module is due for replacement (likely by something written in C/XS), I've opted for something low-effort and less invasive as it were.

      Peeking inside the .ph file on my machines, it's mostly just more requires.

      Yes, the "load a file only once" logic with %INC would apply to every require call. I don't have enough time to test right now, but assuming that those files don't load any other modules, an ugly hack might be { package Foo; local %INC; require "..."; }

      By the way, I took a look at your commit, and I noticed this logic:

      eval { require 'sys/ioctl.ph' }; $Tcl::pTk::_FE_unavailable = $@; ... if ($Tcl::pTk::_FE_unavailable) { ...

      Be aware of Bug in eval in pre-5.14 and that $@ may not be a true value after an eval failure. The better pattern would be for example:

      eval { require 'sys/ioctl.ph'; 1 } or do { $Tcl::pTk::_FE_unavailable = $@||'unknown error'; };

      because in this case $Tcl::pTk::_FE_unavailable will always be a true value if an error occurs, even if $@ is not.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: note [id://1230763]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others admiring the Monastery: (3)
As of 2024-04-19 19:32 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found