3 ms·
> but rather that parameter default values are immutable. No they are not, I’d offer you an example, but you gave one yourself. Are you confused as to what mut
by isitmadeofglass 4y ago
> but rather that parameter default values are immutable.
No they are not, I’d offer you an example, but you gave one yourself. Are you confused as to what mutable and immutable means?
> You absolutely would not expect the value of b to have been influenced by previous calls to visit_city().
Yes they would. Python is not a functional language. If you have A=[1,2,3] and call A.append(4), what do you expect A to be?
Same if you have a function with argument “mylist” and a default set to A, what do you expect to happen to A if you call mylist.append(4) inside that function body on a call that didn’t pass another list?
> Python apologists only offer one positive for this: "It is useful for memoization".
No, that is not the only use, if you couldn’t pass mutable arguments you would cripple the language. And if you couldn’t pass mutable defaults you’d have an odd inconsistent handling of them.
- z9znz 4y agoYou are flat out wrong, and I cannot see any way to make this clear to you. Perhaps this is a language barrier problem? > if you couldn’t pass mutable arguments you would cripple the language This is not about passing mutable arguments. This is about having a default value for a parameter be mutable (unreliable). Yes the arguments in Python functions are mutable. That's not unexpected. What is unexpected is that the default value assigned to a non-provided argument is not consistent. In my example I show that the parameter "visited" has a default value of [] if no argument is passed in. Off the top of my head, Ruby, Javascript, and Swift offer the ability to have default parameter values, and they are all predictably immutable (defaults). Python is the odd one here. I will say no more about this here, because I'm beating a dead horse.
- Spivak 4y agoYou’re missing the essential thing which isn’t mutability but that languages like Ruby have default expressions instead of default values. The default “value” is a factory. You can have mutable default values in Ruby just fine if you make the default expression return a reference to the same object. $a = [] def func(b=$a) b.append 5 end func func # $a is [5, 5] They are absolutely not immutable, they just feel immutable. And even then immutable is technically the wrong word — you can obviously mutate params default or not. What you mean is that each invocation gets its own copy of the default but unless you can deep clone arbitrary objects and globals/singletons (i.e. classes) don’t exist this is impossible. Python has actual default values which while sometimes surprising when those values are mutable it is just as much a valid design choice as expressions and both permit mutation. Default expressions have a different equally crazy footgun side effects. $a = [] def func(b=$a.append(1)) b.append 2 end func func # $a is [1, 2, 1, 2]
- z9znz 4y agoRuby default "values" may indeed be expressions, but the typical use is to provide a value which does not depend on state each time it is provided (and a value which does not share memory with previous or future generations of said value). That quacks like "immutable", or "static". Yes, you can stuff anything, even a reference, into the right hand side of a default parameter definition. But in 17 years of using Ruby, I've never done this, never needed to, and never seen anyone else do it. Granted I don't read source of libraries or Rails (except occasionally), so maybe _somewhere_ someone does this. I've read a few Ruby books over the years and never seen this illustrated as a thing to do, even in the Ruby Cookbook book. (added) To be fair, one thing I have seen which is confusing to people new to programming and applies in Ruby, is if you define a constant EMPTY = [] elsewhere, and you use EMPTY as your default value for a parameter, you will get the same behavior as Python had with just []. That's because EMPTY is a constant reference to an array, but the array is mutable. This would be true for any language which is not immutable. Change the reference? No, that's immutable. Change the contents of the thing it references? Yes. However, [] would appear to any sane person as an immediate new allocation of an empty array, not an unnamed reference to one spot in memory which gets an empty array allocated for it the first time it is encountered. In fact, to be very literal, in the Python example the default value is only [] (empty array) once - the first time. In my visit_city() example, after the first run it is now ["some city"]. But if you read that code, and even if you are interactively debugging, the code itself of course does not change. The code still tells you, "Hey, here's a default empty array []". So this utterly fails the principle of least surprise. We expect when we read code that something which appears to be a literal value (or an expression not based on a variable) will evaluate to exactly what it appears to be. At this point we'll just have to disagree on whether the Python behavior is "sometimes surprising" or "supremely stupid". I would simply put it this way: the use cases for Ruby's (and Swift's and Javascript's and probably any other langauge which offers default function params) fits the more common need, and that Python's opposite behavior is a footgun in a land where people very rarely intentionally want to shoot at feet. Your final Ruby example is obvious in what it will do, and not shocking at all. And you had to go out of your way to allow that behavior. Nobody does this. No beginner would see this, in a guide or a book. No beginner would accidentally decide to do this. But beginner and experienced developers alike would come to Python and do def foo(arg=[]):.
- isitmadeofglass 4y ago> What is unexpected is that the default value assigned to a non-provided argument is not consistent. In my example I show that the parameter "visited" has a default value of [] if no argument is passed in. No you don’t. And calling a mutable value “not consistent” because it’s not immutable is just changing the words used after your mistake of immutable vs mutable. You haven’t done what you think you’ve done because you don’t understand that [] is not “a new empty list every time it is referenced”, but is just a single mutable list. So you’ve provided a default mutable value, which initially is [], but by the nature of being mutable might change in the future. And that is what gets used if there is no value provided. It’s exactly the same behavior as if you define a named variable with an initially empty list, and pass that list to the default. If you want it to be initiated to [] every time no argument is passed, then you need to initiate a new mutable list as the argument on each call. Just like you wouldn’t be able to define a named list once as empty, and expect every call of .append() to give you a new list with only one element. You’ve passed a single list as the default, not a list imitator, or some crazy “spawns new empty lists on references” object. And yes, you could have default arguments only support immutable values, then you would not be able to pass in a whole range of objects in defaults.
- skywhopper 4y agoSorry, but this is truly wild. The only language I’ve ever used that behaves this way is Python and it’s unbelievable to me that this is seen as acceptable behavior.