News for hackers. Stuff that matters.
Re:Why Hy? by Kodiologist on Tuesday May 03, 2022 @10:35AM (#31248845)
In some other Lisps, yes, but Python has its own idea of how function scoping works that generally isn't what you'd want with `let`. For example, in

    (let [a 1]
      (defn foo []
        (setv a 2))
      (foo)
      (print a))
you probably `2` to be printed, but the seeming equivalent Python code

    a = 1
    def foo():
        a = 2
    foo()
    print(a)
prints `1`. Python interprets the assignment as declaring a new local variable. Frankly, Python got scoping wrong (in its quest to eliminate declarations), but here we are. So `let` needs to work around this somehow. The current implementation implicitly adds `global a` or `nonlocal a` as appropriate. (Actually, the name `a` is also mangled so that any references to `a` outside the `let` refer to a different variable.)
Re:Why Hy? by m45t3r on Tuesday May 03, 2022 @02:06PM (#31251456)
For me the example printing `1` makes sense because I think `let` as being something immutable, so I wouldn't expect `setv` to mutate that variable (would expect either a compiler error or the introduction of a new local variable).

But maybe it is because I am familiar with Clojure (where `setv` or equivalents doesn't exist) and not other Lisps.

This would be the equivalent Clojure code anyway:

  user=> (let [a 1] (defn foo [] (def a 2)) (foo) (println a))
  1
  nil
So yeah, makes sense for me. But can understand why some other people would expect the other way though.
Re:Why Hy? by gilch on Tuesday May 03, 2022 @04:04PM (#31252893)
Equivalent in Common Lisp:

    * (let ((a 1))
        (defun foo ()
          (setq a 2))
        (foo)
        (print a))
    
    2
    2
Re:Why Hy? by ashtonbaker on Tuesday May 03, 2022 @11:02AM (#31249195)
this made me wonder - I know I can use global variables inside a function definition:

    a = 1
    def foo():
      x = a
    foo()
so if this 'a' is a new variable, what happens when the name collides with a global variable?

    a = 1
    def foo():
      a = a
    foo()

    > UnboundLocalError: local variable 'a' referenced before assignment
yuck!
Re:Why Hy? by gilch on Tuesday May 03, 2022 @04:23PM (#31253107)
It works if you disambiguate your namespaces:

    >>> a = 1
    >>> def foo():
    ...     a = globals()['a']
    ...     print(a)
    ...
    >>> foo()
    1
Still yuck?
Re:Why Hy? by gilch on Wednesday May 04, 2022 @06:22PM (#31266628)
Here's another way to do it:

  >>> def foo():
  ...     import __main__
  ...     a = __main__.a
  ...     print(a)
  ...
  >>> foo()
  1
Re:Why Hy? by all2 on Tuesday May 03, 2022 @03:40PM (#31252562)
I'm not sure this is so much of a problem? Changing what you name the variable fixes the issue.

Python is generally quite good at having a verbose option to express things, so I'm surprised there's not an explicit way to reference the enclosing scope from an object.

Re:Why Hy? by vegai_ on Tuesday May 03, 2022 @03:40PM (#31252568)
Is there any non-horror piece of code where supporting this latter case would be useful?
Re:Why Hy? by m55au on Tuesday May 03, 2022 @03:47PM (#31252657)
It is not a particularly good example. A better one would be

    a = 1
    def foo():
      x = a
      a = 2
    foo()

    > UnboundLocalError: local variable 'a' referenced before assignment
Basically a name cannot be both global and local inside the same function. Otherwise it would be a total mess.

"a = a" just means assign the value of local variable "a" to a local variable "a", so the error makes sense.

Re:Why Hy? by baq on Tuesday May 03, 2022 @03:56PM (#31252801)
it kinda sorta works when wrapped in a function

  def f():
      a = 1
      def g():
          nonlocal a
          a = 2
      g()
      print(a)
though nonlocal can't be used when referring to global variables... it's kinda bad.
Re:Why Hy? by gilch on Tuesday May 03, 2022 @04:20PM (#31253074)
You can still use `global` though.