I have a doubt about programming languages.

immutability is often preferred in while designing various components of a language, so do immutable collections whose entries are mutable aren't a kind of bug?

for eg A string is super cool in java because no matter what, once a variable is declared String x = "abcd" , 'a','b','c','d' cannot be changed.( but since variable itself is mutable, we can change the value of x. that i know, and not talking about that)

but on the other hand we have an array int[] x = [1,2,3,4] . how stupid is it to allow doing x[1] = 223

you might not find this stupid, but look it at this: the value maintains its identity. if i passed the value of string in a void function, say print(x) , i know it will be printing the value "abcd" in the name of x and be done with it(it could also be a devil and print something else but eh, not the point) there is no way any function could change or damage the value of x without directly accessing x.

But here we have a shitty array x=[1,2,3,4] , you pass it to any function and now its no longer safe. the cute looking print(x) is a devil function which will simply do this : arr[0]= -2000 , and your array will be fucked up.

I guess the terms associated with this phenomenon are pass by reference and effectively final variables

*( not complaining tho, i have recently used this bug/feature into a new functionality , but looks like a terrible code smell)

  • 5
    x is not the value of the array. x is a reference/pointer to an array.

    if you expect the function to not change the data. mark it with const modifier.

    although i agree that everything probably should be "constant by default. mutable by explicit modifier"
  • 1
    @iiii i haven't used java for a long time, is it possible to make variables declared in a function as constant?
    And yes i know somewhat about pointers and references, but saying something is immutable should be applied to the complete data, not just the collection. kotlin has done it somewhat better by defining list and mutable list as collections. when using List<T> , i can be sure that it won't ever get modified . But they have given us more data structures (or rather , renaming the existing ones) instead of solving the root problem problem which is Immutable collection should make everything inside as immutable, even if the collection is of type T:mutable data structure.
    (or something along the similar lines)
  • 2
    You have to look deeper; array[0] is just a reference to some variable, which itself may contain references to other variables and so on (with the exception of primitives, in which case array is in fact immutable - java string is just an example of such array).

    The only way to make such complex data structures truly immutable would be to recursively iterate a significant portion of application's memory, and to copy that whole portion of memory to a new location every time one wants to change some nested value. Not only would that require an unreasonable amount of memory and speed, it would be totally useless. Imagine a program generating a sequence of n Fibonacci numbers; clearly you'd want that sequence to be immutable, so nobody can mess with values. But how would you generate such an immutable sequence? You could either start with an immutable sequence [1, 1] and create a new immutable sequence [1, 1, 2], or you'd use a mutable temp sequence and make it immutable once you're done.
  • 0
    @yowhatthefuck you know, the more i think about your statement, the more i wonder if its a bug at the very core level of structures. so say if a memory that stores some is data is a box, then

    int is "somecode"(i don't want to use data type or data structure word here) that allows adding data to 1 of those boxes, as well as modifying them after the data in boxes is added(aka memory is written)

    string is "somecode" that allows adding to multiple of those boxes , but not modifying them once the data in boxes is added

    array is "somecode2" that holds multiple of "somecode" guys . Array on its own won't allow changing the number of "somecode"s it holds, but the ultimate task of modifying the box data depends on its children subcodes, and not the array itself.
  • 0
    @hitko i just want this: if the topmost collection is declared as immutable, then no matter whatever inside it, that shouldn't change as its just misleading.
    in fibonacci example, i would definitely use a mutable list. but when i want to pass data from one function to another, the another function should not be able to modify the original data at all , if i don't explicitly want that.

    And yes recursively making that structure immutable will be the only possible way to have something like that
  • 0
    @iiii the comment that is before the previous one was for you, i accidentally tagged myself ^_^!
  • 1
    However, in both scenarios you'd have to eventually copy the whole sequence, using twice as much memory as a basic implementation that doesn't guarantee immutability.

    But now that you have this immutable sequence of Fibonacci numbers, let's say you need them sorted given sin(x) because you're interested in some harmonic property of Fibonacci sequence. That proces again takes up to Nlog(N) extra memory, since each operation needs to make a temp mutable copy of array an then convert it to a mutable array.

    So the question is: should fibonacciSequence(n) return a mutable sequence, given that a Fibonacci sequence is constant? If yes, should you make it immutable? If no, what about operations which are supposed to mutate an array so they don't create a performance bottleneck? Should harmonicFibonacciSequence(n) return an immutable array?
  • 1
    @yowhatthefuck the syntax you've used does not guarantee any immutability both for the variable itself and the data it points to.
  • 3
    @yowhatthefuck and it's not a big. You've asked for a plain chunk of memory and you've got a plain chunk of memory. That's it. 🤷‍♂️
  • 2
    There's no bug. The bug is in your expectations,I guess 🤷‍♂️
  • 1
    @yowhatthefuck So since my topmost collection is an array of 1M users, and each user has an address entity, and each address has a locality entity, every attempt to change a property on some locality somewhere in app will check the whole database to determine references, then fail because that locality is used in the database? You know how insanely useless that would be? All just so someone who doesn't understand how computers work can avoid thinking about references and pointers...
  • 5
    you are both right and not.

    All the primitives AND a String are immutable. Period. You can't change their internal values.

    int[] is not a primitive. It's an array. And arrays are objects. https://docs.oracle.com/javase/... . Now, what if we couldn't change objects' internal values? Wouldn't that make our lives kind of a.... hell (leaving FP aside)?

    If you think THIS is annoying, try C or C++. The land where uncertainty and anarchy thrives. In there you can also change string's (or char*'s) chars however you want (as long as you do not exceed the original length); you can as well null every other character in the string if you want to :)
  • 1
    All of the problems with mutability comes from the fact that most languages implement built in collections as reference types. That makes it impossible to make guaranties about mutability.

    Swift is the only language that I know that makes this right. Collections are value types and when you declare them as 'let' instead of 'var' (let is the same as val in Kotlin) the collection is truly immutable. You can not reassign elements.

    You may wonder if this makes it perform slowly because value types need to be copied when passed around. The answer to this is "copy on write semantics".
  • 1
    @hitko > in both the scenarios i would be eventually copying the whole sequence.

    I disagree for my usecase. am not sure am getting it right, but are you saying that if some hypothetical language creates an immutable collection such that wherever it is used , it will be unable to get changed (whatever data type of the collection is).

    So why would that language need to pass such instance by the traditional copying mechanism? The instances of those variables can never change as long as they exist for a particular scope, they should rather just pe passed by reference.

    Although as i write this, i can understand the insane garbage collection it would require. But i believe if researched , this could be optimised to produce even better results

    Although about the Fibonacci example, i agree that it requires a mutable collection for better performance. I guess mutable/immutable datatypes/collections can co exist as they are doing now. But just needs to be more strict in Differences
  • 0
    @netikras in kotlin, i can creat a list of strings/ints which is truely a blackbox. Val a = listof(1,2,3) and that's it. This a will never be changed nor the list nor any internal values. So i don't think it would be hellish.

    Whats hellish for me is when i create this

    Class boy(var g:Int)

    I just made a flawed class where anyone can change the value g for boy if used in list . Why listof(boy1,boy2,boy3) behave differently from the listof(1,2,3,4) ?
  • 1
    By the way, thank you everyone for your interesting inputs
  • 3
    @yowhatthefuck because for listOf(1,2,3) you are creating a collection of primitives. Since the list is immutable, you cannot change the collection.

    When you do listOf(obj1, obj2, obj3) you also create an immutable list. And you cannot change the collection either.

    HOWEVER, you can still do obj3.setName("Dick"); and that is perfectly fine, because you are not changing the COLLECTION. The collection remains immutable - it contains the same set of addresses to objects.

    Ofc you can extend the Obj class and make it immutable, so that it would not have the setName() method exposed - you could pass name via constructor, and that's it. That way you'd get a deeply immutable collection, i.e. neither the collection nor its members' inner values can be mutated.

    It's close to what the flywheel pattern does.
  • 3
    Broadly, procedural languages suck. At least C++ allows one to annotate a type with const, indicating that it's _supposed_ to be immutable, even if it turns out not to be; it then takes some effort to mutate it behind the back of the implied contract.

    But immutability doesn't mean that you have to copy everything all the time at enormous cost; functional data structures are a thing. And besides, even in pure functional languages, nothing is stopping the compiler from implementing the immutable semantics in a lower level representation (e.g. assembly) where things are being mutated all over the place.
  • 0
    I just want to elaborate a little more:

    There are 2 ways of realizing immutability:

    The first way is polymorphism. You are accessing an object through an interface or base class which allows or forbids calls to methods which do mutate the object. Kotlin does this as far as I know.
    The down side of this is that you need an extra interface for each object like list, dictionary, or any other custom type. It's quite explicit and laborious.

    The other (better) way is having some sort of constant concept like the keyword let, val or const.
    And you need custom value types (often struct) in order to make the whole object constant instead of just the reference.

  • 0
    Most languages are missing either the const capability or the value type capability and are forced to use the first way.

    For example C# has a very limited const capability. You can only apply const to some primitive types. And readonly can only be applied to properties or fields, so, not locals and not parameters.

    Kotlin on the other hand does have a proper const capability but it is missing value types.
  • 1
    @Lensflare constancy of the object does not imply constancy of the internal state. Otherwise it just breaks almost any interface.
  • 0
    @iiii that's correct. As soon as you put in some reference type value as part of your object's state, all hope is lost.
    But as long as you keep everything as value types, the compiler can give you const guarantees.
  • 2
    Java Valhalla will implement ValueType


    Any further questions should be submitted to @BrianGoetz on twitter.
  • 0
    @Lensflare no, i mean even non-reference non-primitive objects. The object is meant to be able to mutate its own internal state, unless it was programmed to account for self-constancy.
  • 1
    Im surprised no one mentioned Rust yet. I think it does this really well thanks to defaulting to const and the borrow checker
  • 0
    @iiii mutation of an object's state is essentially mutation of its properties/fields. If those properties are only immutable value type values, then the state of the object is for all purposes immutable. The compiler can optimize stuff and you can do things in parallel and get all the advantages of immutable state.
Add Comment