Beefy Boxes and Bandwidth Generously Provided by pair Networks
No such thing as a small change
 
PerlMonks  

[SOLVED] Get element count of CONSTANT list (aref))

by stevieb (Abbot)
on Mar 12, 2018 at 21:29 UTC ( #1210767=perlquestion: print w/replies, xml ) Need Help??
stevieb has asked for the wisdom of the Perl Monks concerning the following question:

Hello friends and esteemed Monks,

This isn't a problem per-se, just something I've observed and am wondering if there's a way around it.

I am currently building several wildlife cameras that will be attached to my house and some of my cabins, each camera will be attached to a Raspberry Pi, and will stream back results to a central preview server that I will display on a television screen (up to eight inside of a single browser window).

To enhance what I've already got working, I decided that I want pan/tilt capabilities to my cameras, so for the tilt, I'm using a servo (with the servo() capability of RPi::WiringPi), and for the pan, I'm going to use a stepper motor with a ULN2003 integrated circuit, for which I'm now writing a new distribution, RPi::StepperMotor for. Everything is working great thus far, but I have a question specifically related to constant.

Normally, with a list (ie. array in this case), we can get the count of elements and assign it elsewhere:

my $array = [qw(1 2 3)]; my $array_len = @$array; # $array_len == 3

However, in the module I'm writing, I'd prefer to use a constant:

use constant STEPPER_SEQUENCE => [ [qw(1 0 0 1)], [qw(1 0 0 0)], [qw(1 1 0 0)], [qw(0 1 0 0)], [qw(0 1 1 0)], [qw(0 0 1 0)], [qw(0 0 1 1)], [qw(0 0 0 1)], ];

All is still well and great. However, what I can't seem to figure out, is how to extract the count of elements in the constant list. Here is an example. It prints only aref ok. I've tried a few things I've found in the documentation and elsewhere, but I've either overlooked something, or it's not possible to extract the info I want here:

use warnings; use strict; use feature 'say'; use constant STEPPER_SEQUENCE => [ [qw(1 0 0 1)], [qw(1 0 0 0)], [qw(1 1 0 0)], [qw(0 1 0 0)], [qw(0 1 1 0)], [qw(0 0 1 0)], [qw(0 0 1 1)], [qw(0 0 0 1)], ]; # the below line houses the normal "ARRAY(0x...)" use constant STEP_COUNT => STEPPER_SEQUENCE; # ... and because STEPPER_SEQUENCE returns the "ARRAY(0x...)", # this fails: say "const ok" if STEPPER_SEQUENCE == 3; my $aref = [qw(1 2 3)]; say "aref ok" if @$aref == 3;

I have tried:

@{ STEPPER_SEQUENCE } @( STEPPER_SEQUENCE ) (STEPPER_SEQUENCE) @STEPPER_SEQUENCE etc, etc, etdc

Is it that I'm oblivious to something, or is what I'm attempting not possible?

Thanks!

-stevieb

Replies are listed 'Best First'.
Re: Get element count of CONSTANT list (aref))
by haukex (Abbot) on Mar 12, 2018 at 21:37 UTC

    constants are basically just sub FOO () { ... } (Constant Functions). So I first tried your @{ STEPPER_SEQUENCE }, but Perl reminded me: Ambiguous use of @{STEPPER_SEQUENCE} resolved to @STEPPER_SEQUENCE and Global symbol "@STEPPER_SEQUENCE" requires explicit package name. However, once you disambiguate:

    use constant STEPPER_SEQUENCE => [ [qw(1 0 0 1)], [qw(1 0 0 0)], [qw(1 1 0 0)], [qw(0 1 0 0)], [qw(0 1 1 0)], [qw(0 0 1 0)], [qw(0 0 1 1)], [qw(0 0 0 1)], ]; print 0+@{STEPPER_SEQUENCE()}, "\n"; print 0+@{+STEPPER_SEQUENCE}, "\n"; print 0+@{&STEPPER_SEQUENCE}, "\n"; __END__ 8 8 8

    Update: The thread constant vector might be relevant here too. Also added the third example, although note that calls to constant functions with & are not subject to inlining.

      Don't know how I didn't follow that path, probably just because I was focused for so long on it.

      use warnings; use strict; use feature 'say'; use constant STEPPER_SEQUENCE => [ [qw(1 0 0 1)], [qw(1 0 0 0)], [qw(1 1 0 0)], [qw(0 1 0 0)], [qw(0 1 1 0)], [qw(0 0 1 0)], [qw(0 0 1 1)], [qw(0 0 0 1)], ]; use constant STEP_COUNT => 0+@{ STEPPER_SEQUENCE() }; say STEP_COUNT;

      Output:

      8

      Works perfectly! Thanks once again haukex!

      -stevieb

Re: Get element count of CONSTANT list (aref))
by tybalt89 (Priest) on Mar 12, 2018 at 22:17 UTC
    #!/usr/bin/perl # http://perlmonks.org/?node_id=1210767 use strict; use warnings; use constant STEPPER_SEQUENCE => [ [qw(1 0 0 1)], [qw(1 0 0 0)], [qw(1 1 0 0)], [qw(0 1 0 0)], [qw(0 1 1 0)], [qw(0 0 1 0)], [qw(0 0 1 1)], [qw(0 0 0 1)], ]; print STEPPER_SEQUENCE->@* . "\n";

      ++ tybalt89, I had thought about and actually tested that as well, but I can't use that. If I used postfix-deref, then that would force the encompassing distribution (or other consumers) to require 5.20 at minimum, which I refuse to go above 5.10.

      Besides, it results in the same type of behaviour:

      use warnings; use strict; use feature 'say'; use constant STEPPER_SEQUENCE => [ [qw(1 0 0 1)], [qw(1 0 0 0)], [qw(1 1 0 0)], [qw(0 1 0 0)], [qw(0 1 1 0)], [qw(0 0 1 0)], [qw(0 0 1 1)], [qw(0 0 0 1)], ]; use constant STEP_COUNT => STEPPER_SEQUENCE->@*; say STEP_COUNT;

      Output:

      ARRAY(0x17985b8)ARRAY(0x17981f8)ARRAY(0x17c8e68)ARRAY(0x17edc90)ARRAY( +0x17edd80)ARRAY(0x17a7708)ARRAY(0x17ee0c8)ARRAY(0x1805590)
        Besides, it results in the same type of behaviour:

        In list context, yes, but like @{...} you can force it to scalar context: 0+STEPPER_SEQUENCE->@* is 8. And BTW, there is also STEPPER_SEQUENCE->$#* which will returns 7. tybalt89's code forced the scalar context with the dot . operator.

Re: Get element count of CONSTANT list (aref))
by stevieb (Abbot) on Mar 12, 2018 at 22:07 UTC

    For anyone who may be interested, here's the mock-up prototype code I've got so far to turn the stepper motor clockwise (cw()) or counter-clockwise (ccw()). There's a lot of repetitiveness I will be removing, and adding in many more checks etc, but this works quite well thus far:

    package Step; use 5.010; use strict; use warnings; use Carp qw(croak); use Data::Dumper; use RPi::Const qw(:all); use WiringPi::API qw(:perl); our $VERSION = '2.3601'; use constant FULL => 2; use constant HALF => 1; use constant NUM_PINS => 0..3; use constant STEPPER_SEQUENCE => [ [qw(1 0 0 1)], [qw(1 0 0 0)], [qw(1 1 0 0)], [qw(0 1 0 0)], [qw(0 1 1 0)], [qw(0 0 1 0)], [qw(0 0 1 1)], [qw(0 0 0 1)], ]; use constant STEP_COUNT => 0+@{ STEPPER_SEQUENCE() }; sub new { my ($class, %args) = @_; my $self = bless {}, $class; if (! exists $args{pins}){ croak "'pins' parameter is required to use this module\n"; } setup_gpio(); $self->_pins($args{pins}); my $delay = $args{delay} // 0.01; $self->delay($delay); my $speed = $args{speed} // 'half'; $self->speed($speed); return $self; } sub cw { my ($self, $degrees) = @_; my $step_counter = 0; my $pins = $self->_pins; for (1..$self->_turns($degrees)){ for my $gpio_pin (NUM_PINS){ if (STEPPER_SEQUENCE->[$step_counter][$gpio_pin]){ write_pin($pins->[$gpio_pin], HIGH); } else { write_pin($pins->[$gpio_pin], LOW); } } $step_counter += $self->_phases; if ($step_counter >= STEP_COUNT){ $step_counter = 0; } $self->_wait; } for (@$pins){ write_pin($_, LOW); pin_mode($_, INPUT); } } sub ccw { my ($self, $degrees) = @_; my $step_counter = 0; my $pins = $self->_pins; for (1..$self->_turns($degrees)){ for my $gpio_pin (NUM_PINS){ if (STEPPER_SEQUENCE->[$step_counter][$gpio_pin]){ write_pin($pins->[$gpio_pin], HIGH); } else { write_pin($pins->[$gpio_pin], LOW); } } $step_counter += $self->_phases * -1; if ($step_counter < 0){ $step_counter = STEP_COUNT + $self->_phases * -1; } $self->_wait; } for (@$pins){ write_pin($_, LOW); pin_mode($_, INPUT); } } sub speed { my ($self, $speed) = @_; if (defined $speed){ if (! grep {$speed ne $_} qw(full half)){ croak "'speed' parameter must be either 'full' or 'half'\n +"; } $self->{speed} = $speed; } return $self->{speed}; } sub delay { my ($self, $delay) = @_; $self->{delay} = $delay if defined $delay; return $self->{delay}; } sub _wait { my ($self) = @_; select(undef, undef, undef, $self->delay); } sub _pins { my ($self, $pins) = @_; if (defined $pins){ if (@$pins != 4){ croak "the 'pins' parameter must include an aref with four + elements\n"; } for (@$pins){ pin_mode($_, OUTPUT); write_pin($_, LOW); } $self->{pins} = $pins; } return $self->{pins}; } sub _phases { return $_[0]->speed eq 'full' ? FULL : HALF; } sub _turns { my ($self, $degrees) = @_; return $self->_phases == 1 ? int($degrees / 5.625 + 0.5) * 64 : int($degrees / 11.25 + 0.5) * 64; } 1;

    ...and the calling script (the param to ccw() is the degrees in which to turn:

    use warnings; use strict; use lib '.'; use Step; my $s = Step->new( pins => [12, 16, 20, 21], speed => 'full' ); #$s->cw(90); $s->ccw(90);

    Feedback on any part would be appreciated, particularly with the cw() and ccw() method names. I thought about left() and right(), but perhaps those could be ambiguous in certain scenarios. I do totally like them better. Perhaps they could be aliases with the documentation specifying this?

    Update: After some consideration, I think I might alias right(); up() to cw() and left(), down() to ccw(). Thoughts much welcome.

Re: [SOLVED] Get element count of CONSTANT list (aref))
by stevieb (Abbot) on Mar 13, 2018 at 21:36 UTC

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://1210767]
Approved by marto
Front-paged by Corion
help
Chatterbox?
and the monks are chillaxin'...

How do I use this? | Other CB clients
Other Users?
Others examining the Monastery: (11)
As of 2018-06-25 20:07 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?
    Should cpanminus be part of the standard Perl release?



    Results (128 votes). Check out past polls.

    Notices?