in reply to Re: Closures and undefined subs
in thread Closures and undefined subs

I tried the my $blah = sub {}; deref later... with strict in a toy case and you were right it is alright.
If I do the same with my sub it fail with
Use of uninitialized value in subroutine entry at Levels/Level_IV.pm l +ine 437. Can't use string ("") as a subroutine ref while "strict refs" in use a +t Levels/Level_IV.pm line 437.
If I wold use the local on dydt then it would crash with:
Undefined subroutine &Levels::Level_IV::_dydt called at /usr/lib/perl5 +/site_perl/5.8.8/Math/RungeKutta.pm line 74.
So I guess i might have some serious bug and misunderstanding somewhere in my code... Thats why I am here...

Replies are listed 'Best First'.
Re^3: Closures and undefined subs
by ikegami (Patriarch) on Sep 26, 2007 at 15:17 UTC

    So I guess i might have some serious bug and misunderstanding somewhere in my code...

    Yup, right there, *points to a line*.

    Again, we can't debug code we can't see. Provide us with your work.

      The package is called from another file. $level_iii_ref will be calculated by another package in the main file or it has to call the package itself.

      Theres where I tried to make local or lexicla and failed.. but of course all of the _equations_... should be "local".
      sub _equation_air { my ( $args_ref, $level_iii_ref, $y ) = @_; # my $_equation_air = sub { # my $y = shift; # local *_equation_air = sub { # my $y = shift; ...
      Well I hope you still that enthusiastic...
      package Levels::Level_IV; #-------------------------------------------------------------- #Heading: Level_VI.pl #Author: Anonymous #Purpose: Level_VI calculations. #Usage: It's a library. Use only level_iv subroutine. #References: Don Mackay. Multimedia Environmental Models # The Fugacity Approach Second Edition #File formats: No files needed or printed. #Restrictions: Reasonal input. #Notes: This module is free software; you can redistribute it # and/or modify it under the same terms as Perl itself. #-------------------------------------------------------------- use strict; use warnings; #use diagnostics; use Carp; use Exporter; #use List::Util; use List::MoreUtils qw(zip); use Scalar::Util qw(reftype); #use Math::ODE; #Solve N-th Order (O)rdinary (D)ifferential (E)quation +s #use Math::Calculus::Differentiate; #Algebraic Differentiation Engine use Math::RungeKutta; #Runge-Kutta numeric algo. for Differential Equa +tions use Term::Clui; use FileHandle; use Smart::Comments; use Contextual::Return; use Levels::Level_III; our ( @ISA, @EXPORT, @EXPORT_OK, %EXPORT_TAGS, $VERSION ); $VERSION = 0.9; @ISA = qw(Exporter); @EXPORT = qw(level_iv); #non equilibrium unsteady-state flow system sub level_iv { my ( $args_ref, $R, $factor, $level_iii_ref ) = @_; no warnings qw(closure); #'variable will not stay shared' -> switc +hed off #see end of file for possible solution #call level_iii subroutine to generate difusivities and fugacities $level_iii_ref = level_iii($args_ref, $R, $factor) unless $level_i +ii_ref; #choose differentiation algorithm print "\n"; my $routine = choose( 'Algorithm: (use arrow keys and <Return>, or q to qu +it)', 'rk4', 'rk4_auto' ); #initialize y's for the different mediums my @y_med; INPUTY: while (1) { my @try = split m/\s*,\s*/, ask( "Initialize ya, yw, ys and yse: (separate y's with ', +')" ); if ( scalar @try < 4 ) { print "Four (4) arguments needed. Your input was: '@try'.\ +n"; redo INPUTY; } elsif ( "$try[0]$try[1]$try[2]$try[3]" !~ m/ \A \d+ \z /xms ) +{ print "Arguments are not numeric. Your input was: '@try'.\ +n"; redo INPUTY; } else { @y_med = @try; last INPUTY; } } #choose time step, starting and end time my $dt = choose( 'Time step: (use arrow keys and <Return>, or q to + quit)', '0.005', '0.01', '0.02', '0.05', '0.1', '0.2' ); my $t = 0; my $t_final = 1 / $dt; # from 0+step to 1 in that many steps #open file for printing runge-kutta-merson results open my $fh, '>', 'Level_IVa_Caculations.txt' or croak $!; $fh->autoflush(1); #Runge-Kutta-Merson 4th-order method my @iterations; my @output_merson; if ( $routine eq 'rk4_auto' ) { #choose error for the steps in auto mode. my $eps = choose( 'epsilon: (use arrow keys and <Return>, or q to +quit)', '0.000001', '0.00001', '0.0001' ); #invoke runge kutta algorithm and store calculations RK4_AUTO: for my $i ( $t..$t_final ) { ### Differentiating:... % do +ne #print initialisation if ( $i == 0 ) { printf {$fh} "i = %3d t = %16s dt = %16s ya = %20s + " . "yw = %20s ys = %20s yse = %20s\n", $i, $t, $d +t, $y_med[0], $y_med[1], $y_med[2], $y_med[3]; push @iterations, $i; push @output_merson, [ $t, $dt, $y_med[0], $y_med[1], $y_med[2], $y_med +[3] ]; next RK4_AUTO; } #begin calculations after initial print ( $t, $dt, @y_med ) = rk4_auto( \@y_med, \&_dydt, $t, $dt, + $eps ); printf {$fh} "i = %3d t = %16s dt = %16s ya = %20s yw += %20s" . " ys = %20s yse = %20s\n", $i, $t, $dt, $y_med +[0], $y_med[1], $y_med[2], $y_med[3]; push @iterations, $i; push @output_merson, [ $t, $dt, $y_med[0], $y_med[1], $y_med[2], $y_med[3] +]; } } else { #invoke runge kutta algorithm and store calculations RK4: for my $i ( $t..$t_final ) { ### Differentiating:... % do +ne #print initialisation if ( $i == 0 ) { printf {$fh} "i = %3d t = %.3f dt = %.3f ya = %20s + " . "yw = %20s ys = %20s yse = %20s\n", $i, $t, $d +t, $y_med[0], $y_med[1], $y_med[2], $y_med[3]; push @iterations, $i; push @output_merson, [ $t, $dt, $y_med[0], $y_med[1], $y_med[2], $y_med +[3] ]; next RK4; } #begin calculations after initial print ( $t, @y_med ) = rk4( \@y_med, \&_dydt, $t, $dt ); printf {$fh} "i = %3d t = %.3f dt = %.3f ya = %20s yw += %20s" . " ys = %20s yse = %20s\n", $i, $t, $dt, $y_med +[0], $y_med[1], $y_med[2], $y_med[3]; push @iterations, $i; push @output_merson, [ $t, $dt, $y_med[0], $y_med[1], $y_med[2], $y_med[3] +]; } } print "File Level_IVa_Caculations.txt written.\n"; close $fh or croak $!; #_equation and _dydt_* have to be declared in the main routine or +they #would not have access to the $args_ref and $level_iii_ref (closur +es) #level_iv '_equation' for mass is used as helper equation in dydt +function sub _equation_air { my ( $args_ref, $level_iii_ref, $y ) = @_; # my $_equation_air = sub { # my $y = shift; # local *_equation_air = sub { # my $y = shift; #for easy calculations make copies of the parameters (not alia +ses) my ( $Ei, $Gi, $Cbi, $Vi, $Zi ); if ( exists $args_ref->{'-Ea'} and exists $args_ref->{'-Ga'} and exists $args_ref->{'-Cba'} and exists $args_ref->{'-Va'} and exists $args_ref->{'-Za'} ) { $Ei = $args_ref->{'-Ea'}; $Gi = $args_ref->{'-Ga'}; $Cbi = $args_ref->{'-Cba'}; $Vi = $args_ref->{'-Va'}; $Zi = $args_ref->{'-Za'}; } else { croak "No parameter '-Ea', '-Ga', '-Cba', '-Va' or '-Za' f +ound. " . "Differentiation not possible"; } my $f_j1 = $level_iii_ref->[0]{'air'}{'fugacity'}; my $D_j1_i1 = 0; my $D_j1_i2 = $level_iii_ref->[1]{'diffusivity'}{'air-water'}; my $D_j1_i3 = $level_iii_ref->[1]{'diffusivity'}{'air-soil'}; my $D_j1_i4 = 0; my $f_j2 = $level_iii_ref->[0]{'water'}{'fugacity'}; my $D_j2_i1 = $level_iii_ref->[1]{'diffusivity'}{'water-air'}; my $D_j2_i2 = 0; my $D_j2_i3 = $level_iii_ref->[1]{'diffusivity'}{'water-soil'} +; my $D_j2_i4 = $level_iii_ref->[1]{'diffusivity'}{'water-sedime +nt'}; my $f_j3 = $level_iii_ref->[0]{'soil'}{'fugacity'}; my $D_j3_i1 = $level_iii_ref->[1]{'diffusivity'}{'soil-air'}; my $D_j3_i2 = $level_iii_ref->[1]{'diffusivity'}{'soil-water'} +; my $D_j3_i3 = 0; my $D_j3_i4 = 0; my $f_j4 = $level_iii_ref->[0]{'sediment'}{'fugacity'}; my $D_j4_i1 = 0; my $D_j4_i2 = $level_iii_ref->[1]{'diffusivity'}{'sediment-wat +er'}; my $D_j4_i3 = 0; my $D_j4_i4 = 0; my $Dti = $level_iii_ref->[0]{'air'}{'D_total'}; #differential equation for mass my $dydt = ( ( $Ei + $Gi * $Cbi ) + ( $D_j1_i1 * $f_j1 ) + ( $D_j1_i2 * $f_j1 ) + ( $D_j1_i3 * $f_j1 ) + ( $D_j1_i4 * $f_j1 ) + ( $D_j2_i1 * $f_j2 ) + ( $D_j2_i2 * $f_j2 ) + ( $D_j2_i3 * $f_j2 ) + ( $D_j2_i4 * $f_j2 ) + ( $D_j3_i1 * $f_j3 ) + ( $D_j3_i2 * $f_j3 ) + ( $D_j3_i3 * $f_j3 ) + ( $D_j3_i4 * $f_j3 ) + ( $D_j4_i1 * $f_j4 ) + ( $D_j4_i2 * $f_j4 ) + ( $D_j4_i3 * $f_j4 ) + ( $D_j4_i4 * $f_j4 ) - ( $Dti * $y ) ) / ( $Vi * $Zi ); return $dydt; }; #helper _equation for water medium/compartment sub _equation_water { my ( $args_ref, $level_iii_ref, $y ) = @_; #for easy calculations make copies of the parameters (not alia +ses) my ( $Ei, $Gi, $Cbi, $Vi, $Zi ); if ( exists $args_ref->{'-Ew'} and exists $args_ref->{'-Gw'} and exists $args_ref->{'-Cbw'} and exists $args_ref->{'-Vw'} and exists $args_ref->{'-Zw'} ) { $Ei = $args_ref->{'-Ew'}; $Gi = $args_ref->{'-Gw'}; $Cbi = $args_ref->{'-Cbw'}; $Vi = $args_ref->{'-Vw'}; $Zi = $args_ref->{'-Zw'}; } else { croak "No parameter '-Ew', '-Gw', '-Cbw', '-Vw' or '-Zw' f +ound. " . "Differentiation not possible"; } my $f_j1 = $level_iii_ref->[0]{'air'}{'fugacity'}; my $D_j1_i1 = 0; my $D_j1_i2 = $level_iii_ref->[1]{'diffusivity'}{'air-water'}; my $D_j1_i3 = $level_iii_ref->[1]{'diffusivity'}{'air-soil'}; my $D_j1_i4 = 0; my $f_j2 = $level_iii_ref->[0]{'water'}{'fugacity'}; my $D_j2_i1 = $level_iii_ref->[1]{'diffusivity'}{'water-air'}; my $D_j2_i2 = 0; my $D_j2_i3 = $level_iii_ref->[1]{'diffusivity'}{'water-soil'} +; my $D_j2_i4 = $level_iii_ref->[1]{'diffusivity'}{'water-sedime +nt'}; my $f_j3 = $level_iii_ref->[0]{'soil'}{'fugacity'}; my $D_j3_i1 = $level_iii_ref->[1]{'diffusivity'}{'soil-air'}; my $D_j3_i2 = $level_iii_ref->[1]{'diffusivity'}{'soil-water'} +; my $D_j3_i3 = 0; my $D_j3_i4 = 0; my $f_j4 = $level_iii_ref->[0]{'sediment'}{'fugacity'}; my $D_j4_i1 = 0; my $D_j4_i2 = $level_iii_ref->[1]{'diffusivity'}{'sediment-wat +er'}; my $D_j4_i3 = 0; my $D_j4_i4 = 0; my $Dti = $level_iii_ref->[0]{'water'}{'D_total'}; #differential equation for mass my $dydt = ( ( $Ei + $Gi * $Cbi ) + ( $D_j1_i1 * $f_j1 ) + ( $D_j1_i2 * $f_j1 ) + ( $D_j1_i3 * $f_j1 ) + ( $D_j1_i4 * $f_j1 ) + ( $D_j2_i1 * $f_j2 ) + ( $D_j2_i2 * $f_j2 ) + ( $D_j2_i3 * $f_j2 ) + ( $D_j2_i4 * $f_j2 ) + ( $D_j3_i1 * $f_j3 ) + ( $D_j3_i2 * $f_j3 ) + ( $D_j3_i3 * $f_j3 ) + ( $D_j3_i4 * $f_j3 ) + ( $D_j4_i1 * $f_j4 ) + ( $D_j4_i2 * $f_j4 ) + ( $D_j4_i3 * $f_j4 ) + ( $D_j4_i4 * $f_j4 ) - ( $Dti * $y ) ) / ( $Vi * $Zi ); return $dydt; } #helper _equation for soil medium/compartment sub _equation_soil { my ( $args_ref, $level_iii_ref, $y ) = @_; #for easy calculations make copies of the parameters (not alia +ses) my ( $Ei, $Gi, $Cbi, $Vi, $Zi ); if ( exists $args_ref->{'-Es'} and exists $args_ref->{'-Gs'} and exists $args_ref->{'-Cbs'} and exists $args_ref->{'-Vs'} and exists $args_ref->{'-Zs'} ) { $Ei = $args_ref->{'-Es'}; $Gi = $args_ref->{'-Gs'}; $Cbi = $args_ref->{'-Cbs'}; $Vi = $args_ref->{'-Vs'}; $Zi = $args_ref->{'-Zs'}; } else { croak "No parameter '-Es', '-Gs', '-Cbs', '-Vs' or '-Zs' f +ound. " . "Differentiation not possible"; } my $f_j1 = $level_iii_ref->[0]{'air'}{'fugacity'}; my $D_j1_i1 = 0; my $D_j1_i2 = $level_iii_ref->[1]{'diffusivity'}{'air-water'}; my $D_j1_i3 = $level_iii_ref->[1]{'diffusivity'}{'air-soil'}; my $D_j1_i4 = 0; my $f_j2 = $level_iii_ref->[0]{'water'}{'fugacity'}; my $D_j2_i1 = $level_iii_ref->[1]{'diffusivity'}{'water-air'}; my $D_j2_i2 = 0; my $D_j2_i3 = $level_iii_ref->[1]{'diffusivity'}{'water-soil'} +; my $D_j2_i4 = $level_iii_ref->[1]{'diffusivity'}{'water-sedime +nt'}; my $f_j3 = $level_iii_ref->[0]{'soil'}{'fugacity'}; my $D_j3_i1 = $level_iii_ref->[1]{'diffusivity'}{'soil-air'}; my $D_j3_i2 = $level_iii_ref->[1]{'diffusivity'}{'soil-water'} +; my $D_j3_i3 = 0; my $D_j3_i4 = 0; my $f_j4 = $level_iii_ref->[0]{'sediment'}{'fugacity'}; my $D_j4_i1 = 0; my $D_j4_i2 = $level_iii_ref->[1]{'diffusivity'}{'sediment-wat +er'}; my $D_j4_i3 = 0; my $D_j4_i4 = 0; my $Dti = $level_iii_ref->[0]{'soil'}{'D_total'}; #differential equation for mass my $dydt = ( ( $Ei + $Gi * $Cbi ) + ( $D_j1_i1 * $f_j1 ) + ( $D_j1_i2 * $f_j1 ) + ( $D_j1_i3 * $f_j1 ) + ( $D_j1_i4 * $f_j1 ) + ( $D_j2_i1 * $f_j2 ) + ( $D_j2_i2 * $f_j2 ) + ( $D_j2_i3 * $f_j2 ) + ( $D_j2_i4 * $f_j2 ) + ( $D_j3_i1 * $f_j3 ) + ( $D_j3_i2 * $f_j3 ) + ( $D_j3_i3 * $f_j3 ) + ( $D_j3_i4 * $f_j3 ) + ( $D_j4_i1 * $f_j4 ) + ( $D_j4_i2 * $f_j4 ) + ( $D_j4_i3 * $f_j4 ) + ( $D_j4_i4 * $f_j4 ) - ( $Dti * $y ) ) / ( $Vi * $Zi ); return $dydt; } #helper _equation for sediment medium/compartment sub _equation_sediment { my ( $args_ref, $level_iii_ref, $y ) = @_; #for easy calculations make copies of the parameters (not alia +ses) my ( $Ei, $Gi, $Cbi, $Vi, $Zi ); if ( exists $args_ref->{'-Ese'} and exists $args_ref->{'-Gse'} and exists $args_ref->{'-Cbse'} and exists $args_ref->{'-Vse'} and exists $args_ref->{'-Zse'} ) { $Ei = $args_ref->{'-Ese'}; $Gi = $args_ref->{'-Gse'}; $Cbi = $args_ref->{'-Cbse'}; $Vi = $args_ref->{'-Vse'}; $Zi = $args_ref->{'-Zse'}; } else { croak "No parameter '-Ese', '-Ges', '-Cbse', '-Vse' or '-Z +se' " . "found. Differentiation not possible"; } my $f_j1 = $level_iii_ref->[0]{'air'}{'fugacity'}; my $D_j1_i1 = 0; my $D_j1_i2 = $level_iii_ref->[1]{'diffusivity'}{'air-water'}; my $D_j1_i3 = $level_iii_ref->[1]{'diffusivity'}{'air-soil'}; my $D_j1_i4 = 0; my $f_j2 = $level_iii_ref->[0]{'water'}{'fugacity'}; my $D_j2_i1 = $level_iii_ref->[1]{'diffusivity'}{'water-air'}; my $D_j2_i2 = 0; my $D_j2_i3 = $level_iii_ref->[1]{'diffusivity'}{'water-soil'} +; my $D_j2_i4 = $level_iii_ref->[1]{'diffusivity'}{'water-sedime +nt'}; my $f_j3 = $level_iii_ref->[0]{'soil'}{'fugacity'}; my $D_j3_i1 = $level_iii_ref->[1]{'diffusivity'}{'soil-air'}; my $D_j3_i2 = $level_iii_ref->[1]{'diffusivity'}{'soil-water'} +; my $D_j3_i3 = 0; my $D_j3_i4 = 0; my $f_j4 = $level_iii_ref->[0]{'sediment'}{'fugacity'}; my $D_j4_i1 = 0; my $D_j4_i2 = $level_iii_ref->[1]{'diffusivity'}{'sediment-wat +er'}; my $D_j4_i3 = 0; my $D_j4_i4 = 0; my $Dti = $level_iii_ref->[0]{'sediment'}{'D_total'}; #differential equation for mass my $dydt = ( ( $Ei + $Gi * $Cbi ) + ( $D_j1_i1 * $f_j1 ) + ( $D_j1_i2 * $f_j1 ) + ( $D_j1_i3 * $f_j1 ) + ( $D_j1_i4 * $f_j1 ) + ( $D_j2_i1 * $f_j2 ) + ( $D_j2_i2 * $f_j2 ) + ( $D_j2_i3 * $f_j2 ) + ( $D_j2_i4 * $f_j2 ) + ( $D_j3_i1 * $f_j3 ) + ( $D_j3_i2 * $f_j3 ) + ( $D_j3_i3 * $f_j3 ) + ( $D_j3_i4 * $f_j3 ) + ( $D_j4_i1 * $f_j4 ) + ( $D_j4_i2 * $f_j4 ) + ( $D_j4_i3 * $f_j4 ) + ( $D_j4_i4 * $f_j4 ) - ( $Dti * $y ) ) / ( $Vi * $Zi ); return $dydt; } #differential equation for fugacity at start and end times sub _dydt { my ( $t, @y ) = @_; my @dydt; #e.g.: dy/dt = 4 -> y'(t) = 4 -> y(t) = 4t #two different stating points are accepted in this implementat +ion #so two different starting scenarios can be calculated in orde +r to #show how the system runs against a boundary and balances itse +lf #start differentiation at point y0 (air) $dydt[0] = _equation_air( $args_ref, $level_iii_ref, $y[0] ); #$dydt[0] = _equation_air($y[0]); #local #$dydt[0] = $_equation_air->($y[0]);#lexical #start again at a different point y1 (water) $dydt[1] = _equation_water( $args_ref, $level_iii_ref, $y[1] ) +; #start again at a different point y2 (soil) $dydt[2] = _equation_soil( $args_ref, $level_iii_ref, $y[2] ); #start again at a different point y3 (sediment) $dydt[3] = _equation_sediment( $args_ref, $level_iii_ref, $y[3 +] ); return @dydt; } #build resulthahes my @hash_pairs = zip @iterations, @output_merson ; my %res_hash = ( air => { @hash_pairs }, water => { @hash_pairs }, soil => { @hash_pairs }, sediment => { @hash_pairs }, ); #my %res_hash_parameter = ( ); # return wantarray # ? ( \%res_hash, $level_iii_ref ) # : [ \%res_hash, $level_iii_ref ]; return SCALAR { [ \%res_hash, $level_iii_ref ] } BOOL { scalar keys %res_hash > 0 } NUM { keys %res_hash } STR { reftype [] } LIST { \%res_hash, $level_iii_ref } ARRAYREF { [ \%res_hash, $level_iii_ref ] } CODEREF { croak " > Don't use this result as code! < "; } ; } 1; #not correct #sub aus { # my $x = $_[0] + 35; # sub in { return $x * 19 } #beachte ; bei local # return $x + in(); #} #correct #sub aussen { # my $x = $_[0] + 35; # local *innen = sub { return $x * 19 }; # return $x + innen(); #}
Re^3: Closures and undefined subs
by Anonymous Monk on Sep 26, 2007 at 15:26 UTC
    Just to make it more clear:
    Status quo:
    use Math::RungeKutta; sub outer { my $var = sub_from_other_package(); no warnings qw(closure); sub differ { my $y = shift; $var->[...]{...}{...}; etc. ... return $res; } sub dydt { my ($t,@y) = @_; return differ($y); }; ($t, @y) = rkXXX(\@y, \&dydt, $t, $dt); }
    Neither local nor subs declared in lexicals help me out of my misery. The former is undefined the next is used as ""-ref. So There is a bug but what could it be that turns a sub into undefined?
    Hope you still with me and not bored ;)
      use Math::RungeKutta; sub outer { my $var = sub_from_other_package(); my $differ = sub { my $y = shift; $var->[...]{...}{...}; etc. ... return $res; }; my $dydt = sub { my ($t,@y) = @_; return $differ->($y); }; ($t, @y) = rkXXX(\@y, $dydt, $t, $dt); }
      • Removed no warnings qw(closure);.
      • Converted each named sub to an anon sub.
        • Don't forget the semi-colon at the end of the block. sub is like a function when there's no name.
      • Changed \&dydt.
        Will try it out tomorrow. Original code of the whole module (but it needs other 3 not posted and the original main programme) was posted as answer for your demand for original code a bit earlier.