"Having state" often implies mutability, i.e. to be in a given state means the same thing can be in different states/configurations as well.
On the other hand people often also use the word "state" to refer simply to a "current state" of something at a given time, and then under this interpretation there is state in immutable objects.
As you already know, "representing (real world) state at some step/time" does not require mutability on the language level. These immutable objects are state snaphots of a hypothetical mutable object. Operations on them cannot mutate them, but instead derive a new snaphot that represents the new state at a given time after the operation. So working with those snapshot does represent state and state changes and models real world state, but the individual snaphots/immutable objects cannot be mutated.
Whether those immutable objects deserve the monicker "object", I don't really have a opinion on, but I wouldn't outright deny it.
Are they useful in similar ways that mutable objects are? I'd say so.
Immutable objects can still get you polymorphism/subtyping and encapsulation, features often ascribed to object oriented programming.
Having a conceptual reference (oh god another overloaded term) to something does not imply that there is mutable state on the programming language as long as the reference is immutable.
def times(x, y)
if x.is_one?
y
elsif x.is_zero?
x
else
y.add(times(x.decrement, y)
end
end
a) x and y are not mutated.
b) you can implement the called methods on various immutable object types, and the code would work (assuming we send in the same types, and they obey certain protocols but that is yet another different concern): class WeirdString
def init(v)
@val = v
end
def val
@val
end
def is_zero?
@val.empty?
end
def is_one?
@val.length == 1
end
def decrememt
WeirdString.new(@val[0..-2])
end
def add(ws)
WeirdString.new(@val + ws.val)
end
# times(WeirdString.new('abc', 'hi').val → 'hihihi'
Now, you may say the fact that the object has an instance variable means there is state and you'd be right depending on how you define state, but at any rate the state of a given instance of WeirdString is not mutable.There is mutable state on the conceptual level, i.e. what is modelled, but not on the language level abstraction of an object.
There is no mutable data/state on the language level, at least how things are understood in pure functional programming. But of course mutable state in the real world (for lack of a better term) can still be modeled there.