Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Variable getting overwritten in for loop

Tags:

raku

In a for loop, a different variable is assigned a value. The variable which has already been assigned a value is getting assigned the value from next iteration. At the end, both variable have the same value. The code is for validating data in a file. When I print the values, it prints correct value for first iteration but in the next iteration, the value assigned in first iteration is changed. When I print the value of $value3 and $value4 in the for loop, it shows null for $value4 and some value for $value3 but in the next iteration, the value of $value3 is overwritten by the value of $value4

I have tried on rakudo perl 6.c

my $fh= $!FileName.IO.open;
my $fileObject = FileValidation.new( file => $fh );

for (3,4).list {

  put "Iteration: ", $_;
  if ($_ == 4) {
    $value4 := $fileObject.FileValidationFunction(%.ValidationRules{4}<ValidationFunction>, %.ValidationRules{4}<Arguments>);
  }

  if ($_ == 3) {
    $value3 := $fileObject.FileValidationFunction(%.ValidationRules{3}<ValidationFunction>, %.ValidationRules{3}<Arguments>);
  }

  $fh.seek: SeekFromBeginning;

}
like image 828
Abeer Avatar asked Dec 10 '22 02:12

Abeer


2 Answers

TL;DR It's not possible to confidently answer your question as it stands. This is a nanswer -- an answer in the sense I'm writing it as one but also quite possibly not an answer in the sense of helping you fix your problem.

Is it is rw? A first look.

The is rw trait on a routine or class attribute means it returns a container that contains a value rather than just returning a value.

If you then alias that container then you can get the behavior you've described.

For example:

my $foo;
sub bar is rw { $foo = rand }
my ($value3, $value4);
$value3 := bar;
.say for $value3, $value4;
$value4 := bar;
.say for $value3, $value4;

displays:

0.14168492246366005
(Any)
0.31843665763839857
0.31843665763839857

This isn't a bug in the language or compiler. It's just P6 code doing what it's supposed to do.

A longer version of the same thing

Perhaps the above is so far from your code it's disorienting. So here's the same thing wrapped in something like the code you provided.

spurt 'junk', 'junk';

class FileValidation {
  has $.file;
  has $!foo;
  method FileValidationFunction ($,$) is rw { $!foo = rand }
}

class bar {
  has $!FileName = 'junk';
  has %.ValidationRules =
    { 3 => { ValidationFunction => {;}, Arguments => () },
      4 => { ValidationFunction => {;}, Arguments => () } }

  my ($value3, $value4);

  method baz {
    my $fh= $!FileName.IO.open;
    my $fileObject = FileValidation.new( file => $fh );
    my ($value3, $value4);

    for (3,4).list {

      put "Iteration: ", $_;
      if ($_ == 4) {
        $value4 := $fileObject.FileValidationFunction(
          %.ValidationRules{4}<ValidationFunction>, %.ValidationRules{4}<Arguments>);
      }

      if ($_ == 3) {
        $value3 := $fileObject.FileValidationFunction(
          %.ValidationRules{3}<ValidationFunction>, %.ValidationRules{3}<Arguments>);
      }

      $fh.seek: SeekFromBeginning;

      .say for $value3, $value4
    }
  }
}

bar.new.baz

This outputs:

Iteration: 3
0.5779679442816953
(Any)
Iteration: 4
0.8650280000277686
0.8650280000277686

Is it is rw? A second look.

Brad and I came up with essentially the same answer (at the same time; I was a minute ahead of Brad but who's counting? I mean besides me? :)) but Brad nicely nails the fix:

One way to avoid aliasing a container is to just use =.

(This is no doubt also why @ElizabethMattijsen++ asked about trying = instead of :=.)

You've commented that changing from := to = made no difference.

But presumably you didn't change from := to = throughout your entire codebase but rather just (the equivalent of) the two in the code you've shared.

So perhaps the problem can still be fixed by switching from := to =, but in some of your code elsewhere. (That said, don't just globally replace := with =. Instead, make sure you understand their difference and then change them as appropriate. You've got a test suite, right? ;))

How to move forward if you're still stuck

Right now your question has received several upvotes and no downvotes and you've got two answers (that point to the same problem).

But maybe our answers aren't good enough.

If so...

The addition of the reddit comment, and trying = instead of :=, and trying the latest compiler, and commenting on those things, leaves me glad I didn't downvote your question, but I haven't upvoted it yet and there's a reason for that. It's because your question is still missing a Minimal Reproducible Example.

You responded to my suggestion about producing an MRE with:

The problem is that I am not able to replicate this in a simpler environment

I presumed that's your situation, but as you can imagine, that means we can't confidently replicate it at all. That may be the way you prefer to go for reasons but it goes against SO guidance (in the link above) and if the current answers aren't adequate then the sensible way forward is for you to do what it takes to share code that reproduces your problem.

If it's large, please don't just paste it into your question but instead link to it. Perhaps you can set it up on glot.io using the + button to use multiple files (up to 6 I think, plus there's a standard input too). If not, perhaps gist it via, say, gist.github.com, and if I can I'll set it up on glot.io for you.

like image 147
raiph Avatar answered Feb 22 '23 23:02

raiph


What is probably happening is that you are returning a container rather than a value, then aliasing the container to a variable.

class Foo {
    has $.a is rw;
}

my $o = Foo.new( a => 1 );

my $old := $o.a;
say $old; # 1

$o.a = 2;
say $old; # 2

One way to avoid aliasing a container is to just use =.

my $old = $o.a;
say $old; # 1

$o.a = 2;
say $old; # 1

You could also decontainerize the value using either .self or .<>

my $old := $o.a.<>;
say $old; # 1

$o.a = 2;
say $old; # 1

(Note that .<> above could be .self or just <>.)

like image 44
Brad Gilbert Avatar answered Feb 23 '23 00:02

Brad Gilbert