THuG has asked for the wisdom of the Perl Monks concerning the following question:

...or something like that. Okay... this is what I am trying to do, in more lines or less.
struct ( DEVICE => { datetime => '$', devicetype => '$', zip => '$', version => '$'});

my $$entry[3] = new DEVICE;
It didn't like the [], and it didn't like $$ in a my statement, so I wound up with...
struct ( DEVICE => { datetime => '$', devicetype => '$', zip => '$', version => '$'});

my $sn = $entry3;
$$sn = new DEVICE;

Now it doesn't like something. The error is "Modification of a read-only value attempted at verify.pl line 41, <LOG> chunk 1." LOG is a file handle I have open in read-only, and all of this action (save the struct() statement) is inside a while(<LOG>){}. Line 41 is the $$sn = new DEVICE; line.

No where in this script do I write to that file handle. I think the error is bogus, and that it somehow doesn't like the anon reference thingie.

Help?

Thanks,
Travis

Replies are listed 'Best First'.
Re: Anon Struct Instance
by btrott (Parson) on Jul 11, 2000 at 19:20 UTC
    You have:
    $sn = $entry3; $$sn = new DEVICE;
    and then say:
    > I think the error is bogus, and that it somehow doesn't > like the anon reference thingie.
    That's not an anonymous reference. You've set $sn equal to the value of $entry3 and are then trying to use that value as a reference. That's not going to work, because it's not a reference.

    Try this:

    $entry->[3] = new DEVICE;
    Assuming that $entry is an array reference. Isn't it, the first time you tried to use it?

    In addition: you haven't shown us all of your code, but if you're just looping through data and creating a new DEVICE for each line of the data, then adding that to an array... are you by any chance using an incremented loop counter to hold your array index? :)

    If so, you should try this instead:

    push @$entry, new DEVICE;
    which eliminates the need for the "synthetic" array size indicator. For more on this sort of thing, see Mark-Jason Dominus's Return of Program Repair Shop and Red Flags.
Re: Anon Struct Instance
by THuG (Beadle) on Jul 11, 2000 at 19:34 UTC

    Ah, sorry for the confusion, I'll try to clarify. I'll even post all of my code (just don't laugh).

    You are right, it is not a reference or meant to be. I'm trying to create an instance of the struct anonymously. The value stored in the scalar $sn (which was in the third element of the array @entry) is going to be the name of the new struct. If that value were K123456, then $K123456 would be the name of the struct. I know this sort of anonymous calling is valid, I've used it before.

    The actual names will be stored in a hash as keys. Their value pair is simply a count of how many times they are listed in the log files. In the end, when I want to tabulate and output the data, I will call each key out of the hash (foreach my $key (keys(%Unique_SN))) and then call the DEVICE struct associated with it ($$key).

    That much I have done before, but it was with referenced arrays and stuff, never with a struct.

    Anyway, here is my code, or what I have of it so far. It is in an early testing stage, so I don't actually do anything with the data, yet.

    #!c:\perl\bin\ no strict; use File::DosGlob 'glob'; use Class::Struct; use Getopt::Std; use vars qw($opt_a); getopts('a:'); my $logPath = "\\\\" . $opt_a . "\\d\$\\iims\\history"; print "Searching $logPath\n"; struct ( DEVICE => { datetime => '$', devicetype => '$', zip => '$', v +ersion => '$'}); my %Unique_DeviceType; my %Unique_SN; foreach my $logfile (glob("$logPath\\*")){ open (LOG, "<$logfile") or die "Can't open $logfile: $!"; while(<LOG>){ chomp; s/^\s+//; s/\s+$//; s/\s*,\s*/,/g; s/\[|\]//g; next unless length; my @entry = split(/,/, $_); #split entry: Date Time Devic +eType SN ZIP Version my @date = split(/:/, $entry[0]); #create datetime YYYYMM +DDHHMMSS my @time = split(/:/, $entry[1]); my $datetime = $date[2] . $date[1] . $date[0] . $time[0] . $ti +me[1] . $time[2]; my $sn = $entry[3]; $Unique_DeviceType{$entry[2]}++; #Add entry to unique list + of Device Types $Unique_SN{$sn}++; #Add entry to unique list of SNs if ($Unique_SN{$sn} == 1) { #If this is first occurance $$sn = new DEVICE; $$sn->datetime('$datetime'); $$sn->devicetype('$entry[2]'); $$sn->zip('$entry[4]'); $$sn->version('$entry[5]'); } elsif ($datetime > $$sn->datetime) { $$sn->datetime('$datetime'); $$sn->zip('$entry[4]'); $$sn->version('$entry[5]'); } } } foreach my $key (keys(%Unique_SN)){ print $key . "\n"; }
      Ah, so basically, you're trying to assign the DEVICE to a symbolically referenced scalar, whose name is coming from $entry[3]. I would recommend against doing this, and for using a hash instead, to store these DEVICEs. Like this:
      $devices{$sn} = new DEVICE; $devices{$sn}->datetime{$datetime}; # etc.
      If you rearranged your data slightly, you could get rid of one hash.
      # I've snipped out what I consider to be the important bits... # Warning: This is untested code! # First, store the sn count inside the DEVICE, since we have one DEVIC +E per $sn struct ( DEVICE => { datetime => '$', devicetype => '$', zip => '$', v +ersion => '$', sn_count => '$'}); # Get the $sn and other fields here # If this is the first time we see $sn, populate the DEVICE if (!exists $SNs{$sn}) { $SNs{$sn} = new DEVICE; $SNs{$sn}->datetime('$datetime'); # etc. } # update the sn_count for this $sn. $SNs{$sn}->sn_count($SNs{$sn}->sn_count + 1); foreach my $key (keys %SNs) { print "$key\n"; }
      What is your motivation for storing things in symbolically referenced scalars instead of hash elements?

      Alan

RE: Anon Struct Instance
by ferrency (Deacon) on Jul 11, 2000 at 19:24 UTC
    I'm not clear on exactly what you're trying to do here. If all you want to do is create a new DEVICE, and then stick it into an array, you should be able to:

    $entry[3] = new DEVICE;
    I'm not entirely sure what your array is holding. Are you trying to implement an array of arrays or something? I also think you probably don't want to try to use my on an array element (since you can't).

    If you explain more specifically what you're trying to do, or how you're trying to structure your data storage, it would be a lot easier to help.

Re: Anon Struct Instance
by THuG (Beadle) on Jul 11, 2000 at 20:56 UTC

    Ah, I see what you are wanting to do. I will try it. You are right, it will save a hash, and save the anon namespaces, since they will now be referenced from the hash's values.

    I will try.

    Thanks,
    Travis

Re: Anon Struct Instance
by THuG (Beadle) on Jul 11, 2000 at 21:23 UTC

    Whooohooo!! It is working.

    For those of you who are keeping score, here is the final code, and what changes had to be made.

    First, $foo->bar('$blah') puts "$blah" in bar, not the value of $blah. Whoops, stupid mistake.

    %Unique_SN holds the unique serial number as the key and a pointer to the DEVICE struct associated with it as its value.

    I can now 'use strict' agian, and I don't have to use the itermediate $sn. Now to finish this thing. I might be able to dump %Unique_DeviceType, but I'm holding on to it for now.

    Thanks all. I think the orignal was not working because of the $$sn->datetime($datetime) line, not because of the $$sn = new DEVICE line. The failure was, I think, in not dereferencing. It didn't care about the anon $$sn, but $$sn was literally holding a memory address.

    Wait... I think I may have just confused myself. Anyway, it is working, so no need to worry with it. I like this way better.

    #!c:\perl\bin\ use strict; #must find way to use deref in +my statement use File::DosGlob 'glob'; use Class::Struct; use Getopt::Std; use vars qw($opt_a); getopts('a:'); my $logPath = "\\\\" . $opt_a . "\\d\$\\iims\\history"; print "Searching $logPath\n"; struct ( DEVICE => { datetime => '$', devicetype => '$', zip => '$', v +ersion => '$'}); my %Unique_DeviceType; my %Unique_SN; foreach my $logfile (glob("$logPath\\*")){ open (LOG, "<$logfile") or die "Can't open $logfile: $!"; while(<LOG>){ chomp; #pul +l off newline s/^\s+//; #pull + out leading whitespace s/\s+$//; #pull + out trailing whitespace s/\s*,\s*/,/g; #pul +l out whitespace around commas s/\[|\]//g; #re +move [ ] around date time stamp next unless length; #mo +ve to the next line unless there is something left in this one my @entry = split(/,/, $_); #sp +lit entry: Date Time DeviceType SN ZIP Version my @date = split(/:/, $entry[0]); #crea +te datetime YYYYMMDDHHMMSS my @time = split(/:/, $entry[1]); my $datetime = $date[2] . $date[1] . $date[0] . $time[0] . $ti +me[1] . $time[2]; $Unique_DeviceType{$entry[2]}++; #Add e +ntry to unique list of Device Types if (!exists $Unique_SN{$entry[3]}) { #If th +is is first occurance $Unique_SN{$entry[3]} = new DEVICE; #Ad +d entry to unique list of SNs $Unique_SN{$entry[3]}->datetime($datetime); $Unique_SN{$entry[3]}->devicetype($entry[2]); $Unique_SN{$entry[3]}->zip($entry[4]); $Unique_SN{$entry[3]}->version($entry[5]); } elsif ($datetime > $Unique_SN{$entry[3]}->datetime) { #If t +his occurance is newer $Unique_SN{$entry[3]}->datetime($datetime); $Unique_SN{$entry[3]}->zip($entry[4]); $Unique_SN{$entry[3]}->version($entry[5]); } } } foreach my $key (keys(%Unique_SN)){ print $key . "\n"; }
      You wrote:
      > Thanks all. I think the orignal was not working because of the $$sn->datetime($datetime) line,
      > not because of the $$sn = new DEVICE line. The failure was, I think, in not dereferencing. It
      > didn't care about the anon $$sn, but $$sn was literally holding a memory address.

      The -> operator does the dereferencing, but I think
      $$sn->datetime($datetime)

      actually means
      $($sn->datetime($datetime))

      and not
      ($$sn)->datetime($datetime)

      So, it was trying to dereference the wrong thing.

      Glad you got it working! Have fun.

      Alan