How to tell which module Perl is using ?

peterchan75

Supremacy Member
Joined
Apr 26, 2003
Messages
6,754
Reaction score
533
Hi All,

Recently I ran into SSL connection failure with HTTP::Tiny module. When I remove the following form the beginning of the code, the connection problem went away.

Code:
BEGIN {
unshift(@INC, "C:\\Perl64\\lib");
}

Is there a way to tell where is the module the perl script is using ?
Thanks in advance.
 

davidktw

Arch-Supremacy Member
Joined
Apr 15, 2010
Messages
13,550
Reaction score
1,302
Hi All,

Recently I ran into SSL connection failure with HTTP::Tiny module. When I remove the following form the beginning of the code, the connection problem went away.

Code:
BEGIN {
unshift(@INC, "C:\\Perl64\\lib");
}

Is there a way to tell where is the module the perl script is using ?
Thanks in advance.
What do you mean by where ? @INC is the includes path. It's not using any modules

It's the same as export PATH=....
or export LD_LIBRARY_PATH=....

perl modules are imported using "import" statements.

The code you listed above simply say other than the system-wide or vendor-wide preferences, also include the explicitly mentioned path as additional search paths.
 

davidktw

Arch-Supremacy Member
Joined
Apr 15, 2010
Messages
13,550
Reaction score
1,302
Didn't find Perl to be intuitive......
I can only smile. :)
Intuitive comes at different levels.

If things have to be intuitive before you engage, you will be missing out with a lot of good stuffs.

Regular Expressions are super intuitive, but super powerful in lexical parsing and is essential in a lot of works from your compiler design, to webpage extraction to natural language processing.
 

peterchan75

Supremacy Member
Joined
Apr 26, 2003
Messages
6,754
Reaction score
533
:LOL: Not my intention to start a love vs hate perl thread. It's not worth my time to learn python and convert more than 6,000 lines of code.

Any way of knowing those modules loaded by default?
My script never doing any module load programatically. But if I add the script above, HTTP::Tiny failed SSL connection.
 

Trader11

Banned
Joined
Oct 14, 2018
Messages
15,697
Reaction score
5,235
I can only smile. :)
Intuitive comes at different levels.

If things have to be intuitive before you engage, you will be missing out with a lot of good stuffs.

Regular Expressions are super intuitive, but super powerful in lexical parsing and is essential in a lot of works from your compiler design, to webpage extraction to natural language processing.
I find it is easier to write clean code in Python and for other Dev or ops people to understand. If use Perl, then only one or two people will understand.
 

davidktw

Arch-Supremacy Member
Joined
Apr 15, 2010
Messages
13,550
Reaction score
1,302
I find it is easier to write clean code in Python and for other Dev or ops people to understand. If use Perl, then only one or two people will understand.
Depends on who is writing. If software engineering is about easy to read, I think you may have join the wrong faculty :) Easy to read is to target mass, software engineer is not about targeting mass. Try throw a couple of python to layman and ask them what does the python do. If they don't get it, it's not a matter of python is easy to read or not, it's a matter of whether they get what the algorithm is doing. Python can be written in complex manner too.

I could write python as simple as this and some will still not get it
Python:
def nat(n):
    yield n
    yield from nat(n + 1)

def sieve(n):
    i = next(n)
    yield i
    yield from sieve(j for j in n if j % i != 0)
n = sieve(nat(2))
print(next(n))

Focus on competency. Ease of read is not a hard necessity. There is nothing about mathematical thesis that is foundational to CS that is easy. It only seems easy after you learnt. So learn it. :)
 

davidktw

Arch-Supremacy Member
Joined
Apr 15, 2010
Messages
13,550
Reaction score
1,302
Any way of knowing those modules loaded by default?
My script never doing any module load programatically. But if I add the script above, HTTP::Tiny failed SSL connection.
Nope, perl like many programming languages do not auto load modules unless you explicitly requested for it. Although Perl has autoloading feature which I doubt you are using https://docstore.mik.ua/orelly/perl4/prog/ch10_02.htm

@INClude paths merely tell the perl interpreter where in the filesystem should modules be searched, not auto loading them. There could be thousands of modules in the system which your perl program doesn't use.

Bash:
$ perl -V
Summary of my perl5 (revision 5 version 28 subversion 3) configuration:

  Platform:
    osname=darwin
    osvers=20.5.0
    archname=darwin-thread-multi-2level

...

  @INC:
    /opt/local/lib/perl5/site_perl/5.28/darwin-thread-multi-2level
    /opt/local/lib/perl5/site_perl/5.28
    /opt/local/lib/perl5/vendor_perl/5.28/darwin-thread-multi-2level
    /opt/local/lib/perl5/vendor_perl/5.28
    /opt/local/lib/perl5/5.28/darwin-thread-multi-2level
    /opt/local/lib/perl5/5.28

The statements above are the default include paths in my installation, yours may differs, but the idea is the same.
You do not need to augment using @INC unless your modules are in different search spaces.

Bash:
$ perl -e '$,="\n"; print(@INC); print "\n"."="x60,"\n"; unshift(@INC, "/some/path");print(@INC); print "\n"'
/opt/local/lib/perl5/site_perl/5.28/darwin-thread-multi-2level
/opt/local/lib/perl5/site_perl/5.28
/opt/local/lib/perl5/vendor_perl/5.28/darwin-thread-multi-2level
/opt/local/lib/perl5/vendor_perl/5.28
/opt/local/lib/perl5/5.28/darwin-thread-multi-2level
/opt/local/lib/perl5/5.28
============================================================

/some/path
/opt/local/lib/perl5/site_perl/5.28/darwin-thread-multi-2level
/opt/local/lib/perl5/site_perl/5.28
/opt/local/lib/perl5/vendor_perl/5.28/darwin-thread-multi-2level
/opt/local/lib/perl5/vendor_perl/5.28
/opt/local/lib/perl5/5.28/darwin-thread-multi-2level
/opt/local/lib/perl5/5.28

If you want to use the HTTP::Tiny module, import it using
Perl:
use HTTP::Tiny
use HTTP::Tiny () ## not importing any default symbols.

Find out more using perldoc
Bash:
perldoc HTTP::Tiny

Giving you a glimpse into some debugging techniques.

Perl:
$ perl -MData::Dumper -e 'BEGIN { print Dumper(\%INC) }; use HTTP::Tiny; print Dumper(\%INC)'
$VAR1 = {
          'strict.pm' => '/opt/local/lib/perl5/5.28/strict.pm',
          'bytes.pm' => '/opt/local/lib/perl5/5.28/bytes.pm',
          'XSLoader.pm' => '/opt/local/lib/perl5/5.28/XSLoader.pm',
          'Carp.pm' => '/opt/local/lib/perl5/5.28/Carp.pm',
          'overloading.pm' => '/opt/local/lib/perl5/5.28/overloading.pm',
          'Exporter.pm' => '/opt/local/lib/perl5/5.28/Exporter.pm',
          'constant.pm' => '/opt/local/lib/perl5/5.28/constant.pm',
          'warnings/register.pm' => '/opt/local/lib/perl5/5.28/warnings/register.pm',
          'warnings.pm' => '/opt/local/lib/perl5/5.28/warnings.pm',
          'Data/Dumper.pm' => '/opt/local/lib/perl5/5.28/darwin-thread-multi-2level/Data/Dumper.pm'
        };
$VAR1 = {
          'warnings/register.pm' => '/opt/local/lib/perl5/5.28/warnings/register.pm',
          'Errno.pm' => '/opt/local/lib/perl5/5.28/darwin-thread-multi-2level/Errno.pm',
          'POSIX.pm' => '/opt/local/lib/perl5/5.28/darwin-thread-multi-2level/POSIX.pm',
          'Config.pm' => '/opt/local/lib/perl5/5.28/darwin-thread-multi-2level/Config.pm',
          'IO/Handle.pm' => '/opt/local/lib/perl5/5.28/darwin-thread-multi-2level/IO/Handle.pm',
          'bytes.pm' => '/opt/local/lib/perl5/5.28/bytes.pm',
          'Socket.pm' => '/opt/local/lib/perl5/5.28/darwin-thread-multi-2level/Socket.pm',
          'Tie/Hash.pm' => '/opt/local/lib/perl5/5.28/Tie/Hash.pm',
          'IO.pm' => '/opt/local/lib/perl5/5.28/darwin-thread-multi-2level/IO.pm',
          'HTTP/Tiny.pm' => '/opt/local/lib/perl5/5.28/HTTP/Tiny.pm',
          'Carp.pm' => '/opt/local/lib/perl5/5.28/Carp.pm',
          'strict.pm' => '/opt/local/lib/perl5/5.28/strict.pm',
          'Symbol.pm' => '/opt/local/lib/perl5/5.28/Symbol.pm',
          'Exporter.pm' => '/opt/local/lib/perl5/5.28/Exporter.pm',
          'IO/Socket.pm' => '/opt/local/lib/perl5/5.28/darwin-thread-multi-2level/IO/Socket.pm',
          'constant.pm' => '/opt/local/lib/perl5/5.28/constant.pm',
          'warnings.pm' => '/opt/local/lib/perl5/5.28/warnings.pm',
          'Data/Dumper.pm' => '/opt/local/lib/perl5/5.28/darwin-thread-multi-2level/Data/Dumper.pm',
          'XSLoader.pm' => '/opt/local/lib/perl5/5.28/XSLoader.pm',
          'base.pm' => '/opt/local/lib/perl5/5.28/base.pm',
          'overloading.pm' => '/opt/local/lib/perl5/5.28/overloading.pm',
          'Exporter/Heavy.pm' => '/opt/local/lib/perl5/5.28/Exporter/Heavy.pm',
          'IO/Socket/INET.pm' => '/opt/local/lib/perl5/5.28/darwin-thread-multi-2level/IO/Socket/INET.pm',
          'IO/Socket/IP.pm' => '/opt/local/lib/perl5/5.28/IO/Socket/IP.pm',
          'Fcntl.pm' => '/opt/local/lib/perl5/5.28/darwin-thread-multi-2level/Fcntl.pm',
          'IO/Socket/UNIX.pm' => '/opt/local/lib/perl5/5.28/darwin-thread-multi-2level/IO/Socket/UNIX.pm',
          'SelectSaver.pm' => '/opt/local/lib/perl5/5.28/SelectSaver.pm'
        };
 
Last edited:

peterchan75

Supremacy Member
Joined
Apr 26, 2003
Messages
6,754
Reaction score
533
@davidktw,
I manage to locate the module using this command line.
perldoc -l HTTP::Tiny
C:\Perl64\lib\HTTP\Tiny.pm
The above is version 0.048.

Can tell it to go use another one version 0.076 ?
 

davidktw

Arch-Supremacy Member
Joined
Apr 15, 2010
Messages
13,550
Reaction score
1,302
@davidktw,
I manage to locate the module using this command line.
perldoc -l HTTP::Tiny
C:\Perl64\lib\HTTP\Tiny.pm
The above is version 0.048.

Can tell it to go use another one version 0.076 ?
Can you get the 0.076 version installed into your system first ?
If can, you can always override it by what you suggested `unshift` a path into the @INC array.
That will make sure your overwritten module in the path is first searched instead of the system-wide one.

Normally I will suggest using local:lib
https://metacpan.org/pod/local::lib
Still you will need to install a separate library installation of the affected modules, which may also have dependencies, which may break the setup if you didn't include them.

What I normally did in such situation is to use `cpan` and perform an installation of the modules into a separate path and let cpan handle the dependencies to override a need installation of modules into this new path. Then the loading sequence will get things working fine.

:)
 

peterchan75

Supremacy Member
Joined
Apr 26, 2003
Messages
6,754
Reaction score
533
OK. I try the ushift @INC. Thanks.

BTW, I strongly suspect that there is a default that lead perl to find the latest version.
 

peterchan75

Supremacy Member
Joined
Apr 26, 2003
Messages
6,754
Reaction score
533
Just an update. Windows cpan gone crazy.... it pushes modules that I didn't call for.
cpanm seems to do exactly what I want and uninstalling module is easy too.
 

Trader11

Banned
Joined
Oct 14, 2018
Messages
15,697
Reaction score
5,235
Depends on who is writing. If software engineering is about easy to read, I think you may have join the wrong faculty :) Easy to read is to target mass, software engineer is not about targeting mass. Try throw a couple of python to layman and ask them what does the python do. If they don't get it, it's not a matter of python is easy to read or not, it's a matter of whether they get what the algorithm is doing. Python can be written in complex manner too.

I could write python as simple as this and some will still not get it
Python:
def nat(n):
    yield n
    yield from nat(n + 1)

def sieve(n):
    i = next(n)
    yield i
    yield from sieve(j for j in n if j % i != 0)
n = sieve(nat(2))
print(next(n))

Focus on competency. Ease of read is not a hard necessity. There is nothing about mathematical thesis that is foundational to CS that is easy. It only seems easy after you learnt. So learn it. :)
Are there real application usage for yield? To be honest,. I never use yield in my short python career.
 

davidktw

Arch-Supremacy Member
Joined
Apr 15, 2010
Messages
13,550
Reaction score
1,302
Are there real application usage for yield? To be honest,. I never use yield in my short python career.
One generic use of generators is to create ur own iterators. You can use it for pagination implementation. Generators are also implemented in Javascript.

Basically for any looping nature of works where you would like to temporarily suspend that loop and come back to it later and still resume the state before you suspend, you can use generators. Otherwise you will always need to implement your own brew of suspension technique in implementation that doesn’t have generators available.

Iterator concept is vastly used in Java design concepts so that continuous data source input can be presented as a source sink to be consumed by different processing logic. Of course there are different approaches to separate logic and data input flows, such as using callback/lambda functions into the data input flow looping. The difference here is the composition technique, data flow inside processing flow or processing flow inside data flow. You could have multiple data input flows that is composed inside a single processing flow.

So it is up to you to find a good application of it. :)

https://realpython.com/introduction-to-python-generators/
 
Last edited:

peterchan75

Supremacy Member
Joined
Apr 26, 2003
Messages
6,754
Reaction score
533
One generic use of generators is to create ur own iterators. You can use it for pagination implementation. Generators are also implemented in Javascript.

Basically for any looping nature of works where you would like to temporarily suspend that loop and come back to it later and still resume the state before you suspend, you can use generators. Otherwise you will always need to implement your own brew of suspension technique in implementation that doesn’t have generators available.

Iterator concept is vastly used in Java design concepts so that continuous data source input can be presented as a source sink to be consumed by different processing logic. Of course there are different approaches to separate logic and data input flows, such as using callback/lambda functions into the data input flow looping. The difference here is the composition technique, data flow inside processing flow or processing flow inside data flow. You could have multiple data input flows that is composed inside a single processing flow.

So it is up to you to find a good application of it. :)

https://realpython.com/introduction-to-python-generators/
Is that similar to interrupt?
 

davidktw

Arch-Supremacy Member
Joined
Apr 15, 2010
Messages
13,550
Reaction score
1,302
Is that similar to interrupt?
Similar, but interrupts are kernel or hardware level constructs and preemptive. Coroutine and generators are programming language constructs that control the flow of execution, which are non-preemptive (or cooperative). In interrupts, the interrupt handler is required to save states so that it can be restored once the interrupt handler complete. Interrupts can happen in very undesirable situation. Yielding is a voluntary operation by the callee to relinquish control back to the caller. Hence the yielder is always in control on when control is passed and also accepted back. There are differences between the 2 modes of interruption.

Normally functions, once invoked can only be pass back to the caller via a return or exit. Normally functions do not suspend. `yield` keyword in programming languages provide a way to suspend the currently executed function (or threads in some programming languages) and return the execution flow to the caller(function/thread).

Basically it is a flow suspension technique under the same thread/process. One can resume the flow after the `yield` instruction. Invocation of the function do not need to restart from the top of the function. Think if it like suspending your OS and put your system to sleep and then when you start your OS again, you resume from where you left off.

Programs flow is just a collection of memory(registers/heap/stack) state. Yield also allow for data to be injected back into the program flow on next execution. This form of execution manipulation provides both segregation of concern and still inter-interaction between 2 different flows.

Python:
def func_a():
    counter = 0
    while True:
        print("FUNC_A: %d" % counter)
        yield counter
        counter += 1

def func_b():
    counter = 0
    while True:
        print("FUNC_B: %d" % counter)
        yield counter
        counter += 1

a = func_a()
b = func_b()
print(a)
print(b)
counter = 10
while counter > 0:
    next(a)
    next(b)
    counter -= 1

Execution:
Code:
<generator object func_a at 0x7fab9ba635f0>
<generator object func_b at 0x7fab9ba63580>
FUNC_A: 0
FUNC_B: 0
FUNC_A: 1
FUNC_B: 1
FUNC_A: 2
FUNC_B: 2
FUNC_A: 3
FUNC_B: 3
FUNC_A: 4
FUNC_B: 4
FUNC_A: 5
FUNC_B: 5
FUNC_A: 6
FUNC_B: 6
FUNC_A: 7
FUNC_B: 7
FUNC_A: 8
FUNC_B: 8
FUNC_A: 9
FUNC_B: 9

Notice the functions will never cease since each are in infinite loops. Without yield, you will never be able to halt the program normally. But with yield, you can suspend the execution of the function. Of course, this is not why you use such technique. It is the flows that is intended and with it, one does not need to design very complicated iterators functions that can suspend from one iteration to another in a controlled manner. Without it, the technique of the function can get somewhat complicated with the need to return states or using closures to achieve the same flow.

One very useful case is say you have a recursive sudoku solver, but you know a sudoku problem can have multiple solutions. Using generators, you can suspend halfway in a recursive execution for one solution, then return this solution to the caller. If the caller wanted more solutions(if they exist), just resume from where the recursive function suspended. Hope this helps to give you some insights to what are the potential use of it. :)

Note: The above is just superficially scratching the surface of yielding flow control. The caller can also control in the mist of suspension.
Python:
def func():
    counter = 0
    while True:
        print("FUNC: %d" % counter)
        val = (yield counter)
        if val is None:
            counter += 1
        else:
            counter = val
                
f = func()

print(f)
print("OUT: %d" % next(f))
print("OUT: %d" % next(f))
print("OUT: %d" % next(f))
print("OUT: %d" % f.send(20))
print("OUT: %d" % next(f))
print("OUT: %d" % next(f))
print("OUT: %d" % f.send(0))
print("OUT: %d" % next(f))
print("OUT: %d" % next(f))

Execution:
Code:
<generator object func at 0x7fd48421c580>
FUNC: 0
OUT: 0
FUNC: 1
OUT: 1
FUNC: 2
OUT: 2
FUNC: 20
OUT: 20
FUNC: 21
OUT: 21
FUNC: 22
OUT: 22
FUNC: 0
OUT: 0
FUNC: 1
OUT: 1
FUNC: 2
OUT: 2
 
Last edited:

Trader11

Banned
Joined
Oct 14, 2018
Messages
15,697
Reaction score
5,235
Similar, but interrupts are kernel or hardware level constructs and preemptive. Coroutine and generators are programming language constructs that control the flow of execution, which are non-preemptive (or cooperative). In interrupts, the interrupt handler is required to save states so that it can be restored once the interrupt handler complete. Interrupts can happen in very undesirable situation. Yielding is a voluntary operation by the callee to relinquish control back to the caller. Hence the yielder is always in control on when control is passed and also accepted back. There are differences between the 2 modes of interruption.

Normally functions, once invoked can only be pass back to the caller via a return or exit. Normally functions do not suspend. `yield` keyword in programming languages provide a way to suspend the currently executed function (or threads in some programming languages) and return the execution flow to the caller(function/thread).

Basically it is a flow suspension technique under the same thread/process. One can resume the flow after the `yield` instruction. Invocation of the function do not need to restart from the top of the function. Think if it like suspending your OS and put your system to sleep and then when you start your OS again, you resume from where you left off.

Programs flow is just a collection of memory(registers/heap/stack) state. Yield also allow for data to be injected back into the program flow on next execution. This form of execution manipulation provides both segregation of concern and still inter-interaction between 2 different flows.

Python:
def func_a():
    counter = 0
    while True:
        print("FUNC_A: %d" % counter)
        yield counter
        counter += 1

def func_b():
    counter = 0
    while True:
        print("FUNC_B: %d" % counter)
        yield counter
        counter += 1

a = func_a()
b = func_b()
print(a)
print(b)
counter = 10
while counter > 0:
    next(a)
    next(b)
    counter -= 1

Execution:
Code:
<generator object func_a at 0x7fab9ba635f0>
<generator object func_b at 0x7fab9ba63580>
FUNC_A: 0
FUNC_B: 0
FUNC_A: 1
FUNC_B: 1
FUNC_A: 2
FUNC_B: 2
FUNC_A: 3
FUNC_B: 3
FUNC_A: 4
FUNC_B: 4
FUNC_A: 5
FUNC_B: 5
FUNC_A: 6
FUNC_B: 6
FUNC_A: 7
FUNC_B: 7
FUNC_A: 8
FUNC_B: 8
FUNC_A: 9
FUNC_B: 9

Notice the functions will never cease since each are in infinite loops. Without yield, you will never be able to halt the program normally. But with yield, you can suspend the execution of the function. Of course, this is not why you use such technique. It is the flows that is intended and with it, one does not need to design very complicated iterators functions that can suspend from one iteration to another in a controlled manner. Without it, the technique of the function can get somewhat complicated with the need to return states or using closures to achieve the same flow.

One very useful case is say you have a recursive sudoku solver, but you know a sudoku problem can have multiple solutions. Using generators, you can suspend halfway in a recursive execution for one solution, then return this solution to the caller. If the caller wanted more solutions(if they exist), just resume from where the recursive function suspended. Hope this helps to give you some insights to what are the potential use of it. :)

Note: The above is just superficially scratching the surface of yielding flow control. The caller can also control in the mist of suspension.
Python:
def func():
    counter = 0
    while True:
        print("FUNC: %d" % counter)
        val = (yield counter)
        if val is None:
            counter += 1
        else:
            counter = val
                
f = func()

print(f)
print("OUT: %d" % next(f))
print("OUT: %d" % next(f))
print("OUT: %d" % next(f))
print("OUT: %d" % f.send(20))
print("OUT: %d" % next(f))
print("OUT: %d" % next(f))
print("OUT: %d" % f.send(0))
print("OUT: %d" % next(f))
print("OUT: %d" % next(f))

Execution:
Code:
<generator object func at 0x7fd48421c580>
FUNC: 0
OUT: 0
FUNC: 1
OUT: 1
FUNC: 2
OUT: 2
FUNC: 20
OUT: 20
FUNC: 21
OUT: 21
FUNC: 22
OUT: 22
FUNC: 0
OUT: 0
FUNC: 1
OUT: 1
FUNC: 2
OUT: 2
How did you learn all these?????
 
Important Forum Advisory Note
This forum is moderated by volunteer moderators who will react only to members' feedback on posts. Moderators are not employees or representatives of HWZ Forums. Forum members and moderators are responsible for their own posts. Please refer to our Community Guidelines and Standards and Terms and Conditions for more information.
Top