7 ms·
Huh, I've had a wrong understanding of that for over a decade! TIL, thanks.
by ianhorn 6y ago
Huh, I've had a wrong understanding of that for over a decade! TIL, thanks.
- BiteCode_dev 6y agoHey! https://xkcd.com/1053/ https://xkcd.com/1053/ And honestly, I would be rich if I got a dollar every time a student does this: msg.upper() Instead of: msg = msg.upper() And then call me to say it doesn't work.
- cesarb 6y agoIMO, this is a defect in the language: the lack of a "must_use" annotation or similar. If that annotation existed, and the .upper() method was annotated with it, the compiler could warn in that situation.
- diarrhea 6y agoBut you are free to do if title == user_input.upper(): That is, you convert a string to upper without binding the result to a name. You just use it in-place and discard the result, which is fine. With compiler, you mean mypy or linters?
- TkTech 6y agoThat's still "using" the resulting value for a comparison. CPython isn't an optimizing compiler, or it would completely remove the call to upper(). >>> def up(v): ... v.upper() ... >>> dis.dis(up) 2 0 LOAD_FAST 0 (v) 2 LOAD_METHOD 0 (upper) 4 CALL_METHOD 0 6 POP_TOP 8 LOAD_CONST 0 (None) 10 RETURN_VALUE >>> def up(v): ... if v.upper() == "HelloWorld": ... return True ... >>> dis.dis(up) 2 0 LOAD_FAST 0 (v) 2 LOAD_METHOD 0 (upper) 4 CALL_METHOD 0 6 LOAD_CONST 1 ('HelloWorld') 8 COMPARE_OP 2 (==) 10 POP_JUMP_IF_FALSE 16 3 12 LOAD_CONST 2 (True) 14 RETURN_VALUE >> 16 LOAD_CONST 0 (None) 18 RETURN_VALUE Notice in the first example, right after CALL_METHOD the return value on the stack is just immediately POP'd away. The parent is saying that when you run `python example.py` CPython should see that the return value is never used and emit a warning. This would only happen because `upper()` was manually marked using the suggested `must_use` annotation.
- delaaxe 6y agoHe meant that writing a line of code with only contents: msg.upper() should trigger a warning as this clearly doesn't do anything.
- BiteCode_dev 6y agoPython is interpretted, not compiled, and completly dynamic. You cannot check much statically. In fact, any program can replace anything on the fly, and swap your string for something similar but mutable. It's the trade off you make when choosing it.
- pansa2 6y agoI agree, there’s no way to issue a warning about a bare `s.upper()` at compile time. I wonder if it would be possible at runtime?
- nomel 6y agoWhat is this “compile time” you speak of?
- pansa2 6y agoWhen the Python source code is compiled into bytecode.
- nomel 6y agoThat byte code is then interpreted at runtime, so the meaning of s.upper() could change. What something does, when it’s parsed, is not fixed. You can definitely catch most cases at runtime. I’ve done something like this, in an library, to catch a case where people were treating the copy of data as a mutable view. interface[address][slice] = new_values # fancy noop Where a read, modify, write was required: byte_values = interface[address] byte_values[slice] = new_values interface[address] = byte_values It would log/raise a useful error if the there was no assignment/passing of the return value.
- mark-r 6y agoDon't think so, Python doesn't really care if you dispose of the results of an expression. Think about the problems you'd have with ternaries.
- deleted 6y ago[deleted]
- pbowyer 6y ago> And honestly, I would be rich if I got a dollar every time a student does this: > msg.upper() > Instead of: > msg = msg.upper() > And then call me to say it doesn't work. On this, isn't the student's reasoning sensible? E.g. "If msg is a String object that represents my string, then calling .upper() on it will change (mutate) the value, because I'm calling it on itself"? If the syntax was upper(msg) or to a lesser extent String.upper(msg) then the new-to-programming me would have understood more clearly that msg was not going to change. Have you any insights into what your students are thinking?
- BiteCode_dev 6y agoA student don't know anything about mutability, and since Python signatures are not explicit, there is no way to know they have to do that. It's just something to be told. A design decision, like there are thousands to learn in IT, that you just can't guess.
- pansa2 6y ago> String.upper(msg) That was the original syntax [0], before the string functions became methods. I agree that a method more strongly implies mutation than a function does. Also, for consistency with list methods like `reverse` (which acts in place) and `reversed` (which makes a copy), shouldn’t the method be called `uppered`?! [0] https://docs.python.org/2/library/string.html#deprecated-string-functions https://docs.python.org/2/library/string.html#deprecated-str...
- bjoli 6y agoScheme does the right thing here (by convention), that mutating procedures end with a bang: (string-upcase str) returns a new string, whereas (string-upcase! str) mutates the string in place. The details for mutation of data in scheme go beyond that, though. Sometimes procedures are "allowed but not required to mutate their argument". Most (all?) implementations do mutate, but it is still considered bad for to do something like: (define a (list 1 2 3)) (append! a (list 4)) (display a) As append! returns a list that is supposed to supercede the binding to a. Using a like that "is an error", as a valid implementation of append! may look like this (define append! append) Which would make the earlier code snippet invalid.