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

Fellow monks,

I've been beating my head against the wall with this for a couple of days now and still can't figure it out.

I'm writing a TK program that returns a scrollable list based on the user's search parameters and then displays the data in Tk Entry fields on the screen. All well and good, but since my data is set up as a HoAoH, I'm using a ternary expression in the Bind to determine what data I'm going to display.

Here's my code:

$results->bind('<ButtonRelease-1>'=> sub{ $list = $results->curselection; $key eq "year" ? &show($bros->{$data}->[$list]) : $index = 0; while($bros->{$ydx[$list]}->[$index]->{$key} !~ /$data/ +i){ $index++; } $yr = $ydx[$list]; &show($bros->{$ydx[$list]}->[$index]); });

The thing I can't figure out is when my selection key is not "year" the routine works fine. However when it is year, I keep getting a "Tk::Error: Can't modify non-lvalue subroutine call".

I don't understand why this is popping up. I know the values of $data and $list are populated. $data is the year I'm searching on, and $list is the array index from the scrollable list. I've even tried placing static values in that part of the code rather than variables and I still get the same error. Data::Dumper shows that the data is actually in the structure, and the data I want to display, so I'm totally confused. Even more so since the same subroutine call works when my key is anything but "year".

If there is a problem with how I'm sending the data to the subroutine, I can't see it. The subroutine &show is simply taking the data it gets passed, and displaying it in the entry fields.

Any help to clear this up would be greatly appreciated!

There is no emoticon for what I'm feeling now.

Replies are listed 'Best First'.
Re: Need help with binding event in Tk
by keszler (Priest) on Jul 23, 2004 at 06:16 UTC
    Maybe it's just too late for me to think clearly, but why are you using the ternary expression instead of an if/else? It's nice to assign a value, but you're not.

    Also - and this is a guess based on the odd indenting - did you intend that the while loop and following two statements be executed when $key eq "year"?

    Try it this way:

    $results->bind('<ButtonRelease-1>'=> sub{ $list = $results->curselection; if ($key eq "year") { &show($bros->{$data}->[$list]) } else { $index = 0; while($bros->{$ydx[$list]}->[$index]->{$key} !~ /$data +/i){ $index++; } $yr = $ydx[$list]; &show($bros->{$ydx[$list]}->[$index]); });
      I had assumed, and apparently a bit mistakenly, that the ternary could handle more than just variable assignments. I have changed it to an if-else and it's working now. I still can't understand why in the ternary wouldn't evaluate the true part of the expression but would the false.

      As far as the indentation, the while loop actually does activate when the key is not "year". The indentation was merely so that I didn't have a line that extended out 100+ characters and would wrap when I printed the code to look at it on paper.

      There is no emoticon for what I'm feeling now.
        The (or at least a) problem as I saw it is that as written:

        $key eq "year" ? &show($bros->{$data}->[$list]) : $index = 0; while($bros->{$ydx[$list]}->[$index]->{$key} !~ $data/i){ $index++; } $yr = $ydx[$list]; &show($bros->{$ydx[$list]}->[$index]);

        the indentation is hiding what's happening. When written:

        $key eq "year" ? &show($bros->{$data}->[$list]) : $index = 0; while($bros->{$ydx[$list]}->[$index]->{$key} !~ /$data/i){ $index++; } $yr = $ydx[$list]; &show($bros->{$ydx[$list]}->[$index]);

        it is much more obvious that the while loop and two following statements are executed no matter what value $key holds.

Re: Need help with binding event in Tk
by runrig (Abbot) on Jul 23, 2004 at 06:09 UTC
    You have a problem with precedence in this bit of code:
    $key eq "year" ? &show($bros->{$data}->[$list]) : $index = 0;
    Perl thinks you possibly want to assign zero to the function show(). If that is not what you want, put parenthesis arount the $index = 0 part, or use a more conventional if..then..else construct. I'm not fond of using the ternary ?: operator in a void context myself, so I'd opt for the second option.
      Okay that's where I am a bit confused. I thought since I'd defined my conditional, if it was true, then the show sub would execute, and if not, then the other set of code would execute. Since the colon is there, shouldn't that have seperated the two conditions?

      There is no emoticon for what I'm feeling now.
        Check perlop. '?:' has higher precedence than '=', so your code is equivalent to:
        ( ($key eq "year") ? &show($bros->{$data}->[$list]) : $index ) = 0;
        And since you didn't want to return any value (not even an lvalue) from the '?:' operator, you would have been better off using a conventional if (...) {...} else {...} construct. Using '?:' in a void context can be confusing to a maintenance programmer.
Re: Need help with binding event in Tk
by PodMaster (Abbot) on Jul 23, 2004 at 05:23 UTC
    perldoc perldiag
    Can't modify non-lvalue subroutine call

    (F) Subroutines meant to be used in lvalue context should be declared as such, see Lvalue subroutines in the perlsub manpage.
    So whatever is giving you the error is trying to use whatever as an lvalue and whatever is not meant to be used as one. Tk::Error is reporting on it.

    MJD says "you can't just make shit up and expect the computer to know what you mean, retardo!"
    I run a Win32 PPM repository for perl 5.6.x and 5.8.x -- I take requests (README).
    ** The third rule of perl club is a statement of fact: pod is sexy.