Local variable confusion 
Author Message
 Local variable confusion


Quote:

>I'm was busy developing a console app in Dylan when I mistakenly wrote
this
>piece of code:

>  format-out("Do you want to play again? ");
>  let answer :: <string> = read-line(*standard-input*);
>  while (answer = "")
>    format-out("Do you want to play again? ");
>    let answer :: <string> = read-line(*standard-input*);
>  end while;

>The strange thing is, Dylan let me redefine answer without throwing an
error.
>Then, when the program runs, the first read-line works correctly, but if I
hit
>Enter so that the program drops into the while loop, it never comes out
again.
>It seems that the while condition is actually looking at the _original_
answer
>variable and not the newly redefined answer variable.

>I don't understand this behavior, being new to Dylan. Can someone explain
it
>to me?

>Brandon

You cannot assign a new value to an existing binding (variable) with let.
Let always creates a new binding in the smallest enclosing scope (here the
while body). This is the same in C++:

int main()
{
        string answer;
        cin >> answer;
        while (answer == "")
        {
                string answer;
                cin >> answer;
        }       // 2nd answer is destructed here...

Quote:
}

If you want to assign to an existing binding, use the assignment operator
:=

But I guess your problem is nicer solved by using tail recursion, thus not
needing assignment at all:

begin
        local method play(prompt :: <string>, action :: <function>)
                format-out(prompt);
                let answer :: <string> = read-line(*standard-input*);
                if (answer = "")
                        action();
                        play(prompt, action);
                end
        end;

        play("Do you want to play again?\n", method() format-out("playing...\n");
end)
end

(code not checked)

        Gabor



Tue, 04 Sep 2001 03:00:00 GMT  
 Local variable confusion

Thanks for the code.

I understand that you can't assign a new value to an existing binding. That makes
sense to me. But why does Dylan let the code go through? In C++, I would get a
compiler error.

Brandon

Quote:

> You cannot assign a new value to an existing binding (variable) with let.
> Let always creates a new binding in the smallest enclosing scope (here the
> while body). This is the same in C++:

> int main()
> {
>         string answer;
>         cin >> answer;
>         while (answer == "")
>         {
>                 string answer;
>                 cin >> answer;
>         }       // 2nd answer is destructed here...
> }

> If you want to assign to an existing binding, use the assignment operator
> :=

> But I guess your problem is nicer solved by using tail recursion, thus not
> needing assignment at all:

> begin
>         local method play(prompt :: <string>, action :: <function>)
>                 format-out(prompt);
>                 let answer :: <string> = read-line(*standard-input*);
>                 if (answer = "")
>                         action();
>                         play(prompt, action);
>                 end
>         end;

>         play("Do you want to play again?\n", method() format-out("playing...\n");
> end)
> end

> (code not checked)

>         Gabor



Tue, 04 Sep 2001 03:00:00 GMT  
 Local variable confusion
[Apologies for not responding "normally" and hence not getting matching
Message-IDs -- I've just started using Netscape Navigator and can't get
the $%&* thing to reply to News properly :-\]


Quote:
> I'm was busy developing a console app in Dylan when I mistakenly
> wrote this piece of code:

>   format-out("Do you want to play again? ");
>   let answer :: <string> = read-line(*standard-input*);
>   while (answer = "")
>     format-out("Do you want to play again? ");
>     let answer :: <string> = read-line(*standard-input*);
>   end while;

> The strange thing is, Dylan let me redefine answer without throwing
> an error.  Then, when the program runs, the first read-line works
> correctly, but if I hit Enter so that the program drops into the while
> loop, it never comes out again.  It seems that the while condition is
> actually looking at the _original_ answer variable and not the newly
> redefined answer variable.

> I don't understand this behavior, being new to Dylan. Can someone
> explain it to me?

I'll try -- re-reading my explanation before posting, it doesn't seem
too clear ;-)

To quote the DRM (Chapter 14, Table 14-2):

  let        Creates and initializes new local bindings within the
             scope of the smallest enclosing implicit body.

(and from the description below)

  The bindings are visible for the remainder of the [body].

An "implicit body" includes the inside of "define method" and of
"statement macros" like "while", "if", "for" etc.  The macro "let"
creates new bindings (between names and values, or "locations for
values") which last for the rest of the body.  It's valid to re-bind
a name, in the same or a narrower scope, though you might want a
warning from a compiler if you did it in the same scope.

In your code, the first binding of "answer" is in scope in the test
clause of the while loop and in the body of the while loop, right up
until after the second binding of "answer" (which shadows the first)
and again after the while loop (because that's outside the implicit
body where the second binding occurs).

What you want to do would be written like this:

  format-out("Do you want to play again? ");
  let answer :: <string> = read-line(*standard-input*);
  while (answer = "")
    format-out("Do you want to play again? ");
    answer := read-line(*standard-input*);
  end while;

where ":=" changes the value bound to the name "answer", rather than
creating a new binding (with a separate "location").

Or, you could abbreviate it like this:

  local method ask () => (answer :: <string>)
    format-out("Do you want to play again? ");
    read-line(*standard-input*)
  end;
  let answer :: <string> = "";
  while ((answer := ask()) = "")
  end;

Does that help?

Hugh G. Greene



Tue, 04 Sep 2001 03:00:00 GMT  
 Local variable confusion

Quote:

> It's valid to re-bind a name, in the same or a narrower scope, though you
> might want a warning from a compiler if you did it in the same scope.

Yes! That's what I want ... Can I get it? :> It seems a little too tricky
for a normal person (like me) to catch. It'd be nice to have a
"redefinition" warning or something similar.

Quote:

> Does that help?

> Hugh G. Greene

Much, thanks for the explanation.

Brandon



Tue, 04 Sep 2001 03:00:00 GMT  
 Local variable confusion

Quote:

>> int main()
>> {
>>         string answer;
>>         cin >> answer;
>>         while (answer == "")
>>         {
>>                 string answer;
>>                 cin >> answer;
>>         }       // 2nd answer is destructed here...
>> }
> In C++, I would get a compiler error.

No you wouldn't.  Declaring variables local to a {} has a pedigree that goes
back to C.


Tue, 04 Sep 2001 03:00:00 GMT  
 Local variable confusion


Quote:

>> In C++, I would get a compiler error.

> No you wouldn't.  Declaring variables local to a {} has a pedigree that goes
> back to C.

Actually, it goes back quite a bit further (at least Algol60)

Hartmann Schaffer



Tue, 04 Sep 2001 03:00:00 GMT  
 Local variable confusion


Quote:


>>> In C++, I would get a compiler error.

>> No you wouldn't.  Declaring variables local to a {} has a pedigree that goes
>> back to C.

>Actually, it goes back quite a bit further (at least Algol60)

The 1980 vintage pdp-11 C compiler only allowed variable declarations
at the beginning of a function, not at the beginning of a block.
Actually, it might have allowed variable declarations at the beginning of a block, but you were not allowed to declare a variable that was already
declared in the containing context.  If you did, you would get the error
"foo redeclared".


Wed, 05 Sep 2001 03:00:00 GMT  
 Local variable confusion


Quote:




>>>> In C++, I would get a compiler error.

>>> No you wouldn't.  Declaring variables local to a {} has a pedigree that goes
>>> back to C.

>>Actually, it goes back quite a bit further (at least Algol60)

> The 1980 vintage pdp-11 C compiler only allowed variable declarations

Which C compiler was that?  I have never seen one (going back to 1978)
where declarations could only be given at the beginning of a
function.  This is a pure Pascalism that was a regression from Algol60
in the name of compiler simplification.

Quote:
> at the beginning of a function, not at the beginning of a block.
> Actually, it might have allowed variable declarations at the
> beginning of a block, but you were not allowed to declare a variable
> that was already

Yes, declarations had to be at the beginning of the block

Quote:
> declared in the containing context.  If you did, you would get the error
> "foo redeclared".

Please specify which compiler that was.  It is definitely NOT true for
any of the Unix compilers

Hartmann Schaffer
schaffer at netcom dot ca



Wed, 05 Sep 2001 03:00:00 GMT  
 
 [ 9 post ] 

 Relevant Pages 

1. local variable confusion

2. local variable confusion

3. local variable and local variable in block behave differently

4. Sequence local = local variable?

5. Local variables - lifetime and access variables [Q]

6. accessing a local variable in from a widgets -variable or -command properties

7. missing data from variables, confusion over split

8. Confusion in variable scope & mega widget construction

9. variable name and type confusion...

10. Variables confusion

11. Beginner J questions: local variables

12. local variables in functions

 

 
Powered by phpBB® Forum Software