←back to thread

317 points est | 4 comments | | HN request time: 0.874s | source
Show context
gbfowler ◴[] No.17448582[source]
It is not syntactic sugar, "x := 10" is an assignment expression in contrast with "x = 10", which is a statement.

Hence the former can be used in contexts like "if x := 10: pass", which is the whole point of the PEP.

replies(2): >>17448624 #>>17448651 #
Aardwolf ◴[] No.17448624[source]
Why is it not syntactic sugar? It looks like convenience. You could argue everything above machine language is syntactic sugar.
replies(5): >>17448721 #>>17448736 #>>17448847 #>>17448880 #>>17448984 #
chriswarbo ◴[] No.17448984[source]
> You could argue everything above machine language is syntactic sugar.

You could, but that would turn "syntactic sugar" into a useless phrase with arbitrary meaning.

The phrase "syntactic sugar" is usually reserved for language constructs which can always be rewritten, in-place, to some other construct in the same language, such that the semantics is identical (i.e. we can't tell which construct was used, unless we parse the contents of the file).

Python has examples like `foo += bar` being sugar for `foo = foo + bar`.

As an aside, your mention of "machine language" implies the use of operational semantics. That's where we say the "meaning" of a program depends on what it does to the machine when executed. That's fine, but it's not the only approach to semantics. In particular denotational semantics defines the meaning of a program by giving a meaning to each syntactic element of the language and their combinations, usually by rewriting them into some other, well-defined language (e.g. set theory). I much prefer denotational semantics, since it lets me 'think in the language', rather than making me 'think like the machine'.

replies(1): >>17449062 #
uryga ◴[] No.17449062[source]
> Python has examples like `foo += bar` being sugar for `foo = foo + bar`.

Nitpick, but I don't think that's true – AFAIK they translate into different method calls.

    `foo + bar` →`foo.__add__(bar)`

    `foo += bar` → `foo.__iadd__(bar)`
(note the `i` in the second one)
replies(1): >>17449776 #
1. chriswarbo ◴[] No.17449776[source]
Hmm, good catch. Interestingly, I considered using `a + b` as sugar for `a.__add__(b)`, but rejected that because they're not quite equivalent. For example if `__add__` is defined using a magic method:

    >>> class A(object):
    ...   def __getattribute__(self, attr):
    ...     if attr == "__add__":
    ...       return lambda *_: "hello world"
    ...     return None
    ...
    >>> a = A()
    >>> a.__add__(A())
    'hello world'
    >>> a + A()
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    TypeError: unsupported operand type(s) for +: 'A' and 'A'
replies(1): >>17452560 #
2. bilboa ◴[] No.17452560[source]
This is because the actual translation of `a + b` is a little more complicated. It's something like this:

  if '__add__' in a.__dict__:
      try:
          return a.__add__(b)
      except NotImplemented:
          if '__radd__' in b.__dict__:
            return b.__radd__(a)
  elif '__radd__' in b.__dict__:
      return b.__radd__(a)
  
  raise TypeError('unsupported operand type(s) for +: '{}' and '{}'.format(type(a), type(b))
In particular, the runtime seems to directly look for '__add__' in the object's __dict__, rather than just trying to invoke `__add__`, so your `__getattribute__` method isn't enough to make it work. If you add an actual `__add__` method to A your example will work.
replies(1): >>17452949 #
3. chriswarbo ◴[] No.17452949[source]
Yeah, I had a feeling the real 'expansion' would be more involved. I didn't know about the lookup in __dict__, that's good to know.

I'm reminded of PHP, where (at least in version 5.*) we could write:

    $myObject->foo = function() { return "hello world"; };

    $x = $myObject->foo;
    $x(); // Hello world

    $myObject->foo();  // Error: no such method 'foo'
(Taken from an old comment https://news.ycombinator.com/item?id=8119419 )
replies(1): >>17453736 #
4. bilboa ◴[] No.17453736{3}[source]
I found the official docs on how python special methods are looked up.

https://docs.python.org/3/reference/datamodel.html#special-l...

Apparently the runtime is even more picky than I showed. The method has to be defined on the object's type, not in the object's instance dictionary. So, really the lookup is something like:

  if hasattr(type(a), '__add__'):
The link I provided explains the rationale for bypassing the instance dictionary and `__getattribute__` method.