I have read almost every definition of immutable/mutable variables on the internet but as a beginner I just do not grasp it fully so I was wondering if someone could really explain it in layman terms.
Immutable variables (or objects) in any programming language is what I understand when you cannot change the value of that variable after it has been assigned a value. For example, I am using the Haskell programming language, and I write:
let x = 5
Since Haskell has immutable variables, x can never have any other value than 5. So if I after that line of code write:
x = 2
I have in fact not changed the value of x but made a new variable with the same name, which will now be the one that is referenced when I call x, so after both lines of code I can only reach an x with the value of 2.
But what is a mutable variable then, and what programming languages have it? This is where it gets foggy for me. Because when people say mutable variable, they are obviously referring to a variable or object which value you can indeed change after it has been assigned an initial value.
Does this mean that if you have a mutable variable you actually manipulate that place in the computers memory for that variable, and in case of immutable variable you cannot manipulate that place in the computers memory or what?
I don't know how to explain my question any further, as I said, I understand that mutable = can change value of variable after initial value assignment, immutable = cannot. I get the definition. But I don't understand what it actually means in terms of what is going on "behind the scenes". I guess I am looking for easy examples on actual mutable variables.
This has nothing to do with immutability
let x = 5
x = 2
This is reassignment and definitely not allowed in Haskell
First let's look at a regular let assignment
Prelude> let x = 5 in x
5
it :: Num a => a
You can bind x using let, and rebind a new x in a nested let – this effectively shadows the outer x
Prelude> let x = 5 in let x = 2 in x
2
it :: Num a => a
Remember a let is basically a lambda
Prelude> (\x -> x) 5
5
it :: Num a => a
And of course a lambda can return a lambda; illustrates shadowing agian
Prelude> (\x -> (\x -> x)) 5 2
2
it :: Num a => a
I believe a shorthand answer to your question would be that a Mutable variable that holds a value that you would later want to be adjusted.
Depending on the language you're using is its method.
In Kotlin val and var are used to declare variables.
val is a constant while var is adjustable.
Mutable respectively immutable does not concern the variables but the values. Note: one also says the type is (im-)mutable.
For instance if the value is of an immutable type StudentCard, with fields ID and Name, then after creation the fields no longer can be changed. On a name change the student card must be reissued, a new StudentCard must be created.
A more elementary immutable type is String in java. Assigning the same value to two variables is no problem as one variable may not change the shared value. Sharing a mutable value could be dangerous.
A commont mutable type is the array in java and others. Sharing an array, say storing an array parameter in a field, risks that somewhere else the array content is changed inadvertently changing your field.
Related
In SML,if I am correct, variables are immutable by default. So when we try to redefine a variable
val y = 100;
val y = 0.6;
y
the environment will have two entries for y. The new entry hides the original entry.
Isn't it the same effect as if we modified the value in the original entry from 100 to 0.6?
If the original entry was created outside a function call, and the new entry was created in a function call, then when the function call returns, we can access the original entry.
If both entries were created in the same "scope", like the example above, is the original entry not accessible?
Effectively, isn't it the same in SML as in an imperative language such as C? What is the point of making a variable immutable in SML and creating a new entry when redefining a variable?
Thanks.
Isn't it the same effect as if we modified the value in the original entry from 100 to 0.6
No. Consider code that references the previous environment through use of a closure like
val x = 7
val f = fn () => x
val x = 8
val _ = print (Int.toString (f ())) (* prints 7 *)
If the original entry was created outside a function call, and the new entry was created in a function call, then when the function call returns, we can access the original entry.
Sure, its statically scoped.
If both entries were created in the same "scope", like the example above, is the original entry not accessible?
It is still accessible, just not by that identifier. Consider the example above.
What is the point of making a variable immutable in SML and creating a new entry when redefining a variable?
One use of this is changing the type of a variable while still using the same identifier (which you do in the example you post!). Take for instance (in C):
int i = 7;
i = 7.0;
Here, i will still be of type int. Cf., in SML:
val i : int = 7
val i : real = 7.0
I've added type annotations for illustration, but even without this has the same behaviour. After the second binding, i has type real.
To amend kopecs' answer:
What is the point of making a variable immutable in SML and creating a new entry when redefining a variable?
That is the wrong way to phrase the question. :) Immutability by default has many merits, but that would be off-topic.
The actual question is: Why does SML allow multiple bindings for the same variable in a single scope? Instead of making it an error?
And that's a fair question. There is no deep reason. It merely turns out to be convenient sometimes. For example, to avoid spurious identifier clashes when using open. Or to allow redefining previous definitions in an interactive session.
I've read a number of articles on the difference between assignment and binding, but it hasn't clicked yet (specifically in the context of an imperative language vs one without mutation).
I asked in IRC, and someone mentioned these 2 examples illustrate the difference, but then I had to go and I didn't see the full explanation.
Can someone please explain how/why this works in a detailed way, to help illustrate the difference?
Ruby
x = 1; f = lambda { x }; x = 2; f.call
#=> 2
Elixir
x = 1; f = fn -> x end; x = 2; f.()
#=> 1
I've heard this explanation before and it seems pretty good:
You can think of binding as a label on a suitcase, and assignment as a
suitcase.
In other languages, where you have assignment, it is more like putting a value in a suitcase. You actually change value that is in the suitcase and put in a different value.
If you have a suitcase with a value in it, in Elixir, you put a label on it. You can change the label, but the value in the suitcase is still the same.
So, for example with:
iex(1)> x = 1
iex(2)> f = fn -> x end
iex(3)> x = 2
iex(4)> f.()
1
You have a suitcase with 1 in it and you label it x.
Then you say, "Here, Mr. Function, I want you to tell me what is in this suitcase when I call you."
Then, you take the label off of the suitcase with 1 in it and put it on another suitcase with 2 in it.
Then you say "Hey, Mr. Function, what is in that suitcase?"
He will say "1", because the suitcase hasn't changed. Although, you have taken your label off of it and put it on a different suitcase.
After a while, I came up with the answer that is probably the best explanation of the difference between “binding” and “assignment”; it has nothing in common with what I have written in another answer, hence it’s posted as a separate answer.
In any functional language, where everything is immutable, there is no meaningful difference between terms “binding” and “assignment.” One might call it either way; the common pattern is to use the word “binding,“ explicitly denoting that it’s a value bound to a variable. In Erlang, for instance, one can not rebound a variable. In Elixir this is possible (why, for God’s sake, José, what for?)
Consider the following example in Elixir:
iex> x = 1
iex> 1 = x
The above is perfectly valid Elixir code. It is evident, one cannot assign anything to one. It is neither assignment nor binding. It is matching. That is how = is treated in Elixir (and in Erlang): a = b fails if both are bound to different values; it returns RHO if they match; it binds LHO to RHO if LHO is not bound yet.
In Ruby it differs. There is a significant difference between assignment (copying the content,) and binding (making a reference.)
Elixir vs Ruby might not be the best contrast for this. In Elixir, we can readily "re-assign" the value of a previously assigned named variable. The two anonymous-function examples you provided demonstrate the difference in how the two languages assign local variables in them. In Ruby, the variable, meaning the memory reference, is assigned, which is why when we change it, the anonymous function returns the current value stored in that memory-reference. While in Elixir, the value of the variable at the time the anonymous function is defined (rather than the memory reference) is copied and stored as the local variable.
In Erlang, Elixir's "parent" language, however, variables as a rule are "bound." Once you've declared the value for the variable named X, you are not allowed to alter it for the remainder of the program and any needed alterations would need to be stored in new named variables. (There is a way to reassign a named variable in Erlang but it is not the custom.)
Binding refers to particular concept used in expression-based languages that may seem foreign if you're used to statement-based languages. I'll use an ML-style example to demonstrate:
let x = 3 in
let y = 5 in
x + y
val it : int = 8
The let... in syntax used here demonstrates that the binding let x = 3 is scoped only to the expression following the in. Likewise, the binding let y = 5 is only scoped to the expression x + y, such that, if we consider another example:
let x = 3 in
let f () =
x + 5
let x = 4 in
f()
val it : int = 8
The result is still 8, even though we have the binding let x = 4 above the call to f(). This is because f itself was bound in the scope of the binding let x = 3.
Assignment in statement-based languages is different, because the variables being assigned are not scoped to a particular expression, they are effectively 'global' for whatever block of code they're in, so reassigning the value of a variable changes the result of an evaluation that uses the same variable.
The easiest way to understand the difference, would be to compare the AST that is used by the language interpreter/compiler to produce machine-/byte-code.
Let’s start with ruby. Ruby does not provide the AST viewer out of the box, so I will use RubyParser gem for that:
> require 'ruby_parser'
> RubyParser.new.parse("x = 1; f = -> {x}; x = 2; f.()").inspect
#=> "s(:block, s(:lasgn, :x, s(:lit, 1)),
# s(:lasgn, :f, s(:iter, s(:call, nil, :lambda), 0, s(:lvar, :x))),
# s(:lasgn, :x, s(:lit, 2)), s(:call, s(:lvar, :f), :call))"
The thing we are looking for is the latest node in the second line: there is x variable inside the proc. In other words, ruby expects the bound variable there, named x. At the time the proc is evaluated, x has a value of 2. Hence the the proc returns 2.
Let’s now check Elixir.
iex|1 ▶ quote do
...|1 ▶ x = 1
...|1 ▶ f = fn -> x end
...|1 ▶ x = 2
...|1 ▶ f.()
...|1 ▶ end
#⇒ {:__block__, [],
# [
# {:=, [], [{:x, [], Elixir}, 1]},
# {:=, [], [{:f, [], Elixir}, {:fn, [], [{:->, [], [[], {:x, [], Elixir}]}]}]},
# {:=, [], [{:x, [], Elixir}, 2]},
# {{:., [], [{:f, [], Elixir}]}, [], []}
# ]}
Last node in the second line is ours. It still contains x, but during a compilation stage this x will be evaluated to it’s currently assigned value. That said, fn -> not_x end will result in compilation error, while in ruby there could be literally anything inside a proc body, since it’ll be evaluated when called.
In other words, Ruby uses a current caller’s context to evaluate proc, while Elixir uses a closure. It grabs the context it encountered the function definition and uses it to resolve all the local variables.
At first, I thought that set! assignment in scheme is more like assignment = in python other than in c/c++.
in python:
>>> x = 1
>>> id(x)
15855960
>>> x = 2
>>> id(x)
15855936 # different from above!
the second assignment means rebind variable/name to another value instead of overwrite original value in memory location of x.
But c/c++ is the latter case:
int x = 1;
cout << &x << endl; // 0x7ffe3e6adba4
x = 2;
cout << &x << endl; // 0x7ffe3e6adba4 (the same memory location!)
But in 1.3 section of R6RS:
Scheme allows identifiers to stand for locations containing
values. These identifiers are called variables. In many
cases, specifically when the location’s value is never modified
after its creation, it is useful to think of the variable
as standing for the value directly.
And in 1.8 Assignment section:
Scheme variables bound by definitions or let or lambda
expressions are not actually bound directly to the objects
specified in the respective bindings, but to locations
containing these objects. The contents of these locations
can subsequently be modified destructively via assignment.
So it seems in scheme assignment set! is just like what c/c++ assignment = does?
But then how to explain the following:
=> (define x 10)
=> x
10
=> (set! x "lonnnnnnnnnnnnng")
=> x
"lonnnnnnnnnnnnng"
At first x is a location to store an small integer. But later set! put a LONG string into that SMALL memory location? But the location have no enough memory space to do that I think?
Both the citations from the manual say the same thing: an identifier (e.g. a thing like x or y), is associated (“bound”) to a location (a memory cell, e.g. the cell at address 0x7ffe3e6adba4), that can hold different values (for instance an integer, a string etc.), and that the content of the location can be modified with a new value. That is:
Identifier -> Location -> Value
The value, depending from the combination language/compiler, can be either a direct value (or an “unboxed” values, as sometimes it is called, typically in case of values like integers or float), or a “boxed” value, that is a pointer to some memory area the contains the value (typically for complex values like cons cells, arrays, strings, etc.).
As I said, the key point is that the implementation is free to chose how to store values in location, for instance if use a uniform method of storing values according to their type, if optimize and allocate values with different strategies, etc. The only important thing is to strictly follow the specification of the language that requires the double map above. The crucial point here is that in languages like Lisp pointers are (and should remain) “invisible” to the user (the programmer).
I'm trying to make a function that defines a vector that varies based on the function's input, and set! works great for this in Scheme. Is there a functional equivalent for this in OCaml?
I agree with sepp2k that you should expand your question, and give more detailed examples.
Maybe what you need are references.
As a rough approximation, you can see them as variables to which you can assign:
let a = ref 5;;
!a;; (* This evaluates to 5 *)
a := 42;;
!a;; (* This evaluates to 42 *)
Here is a more detailed explanation from http://caml.inria.fr/pub/docs/u3-ocaml/ocaml-core.html:
The language we have described so far is purely functional. That is, several evaluations of the same expression will always produce the same answer. This prevents, for instance, the implementation of a counter whose interface is a single function next : unit -> int that increments the counter and returns its new value. Repeated invocation of this function should return a sequence of consecutive integers — a different answer each time.
Indeed, the counter needs to memorize its state in some particular location, with read/write accesses, but before all, some information must be shared between two calls to next. The solution is to use mutable storage and interact with the store by so-called side effects.
In OCaml, the counter could be defined as follows:
let new_count =
let r = ref 0 in
let next () = r := !r+1; !r in
next;;
Another, maybe more concrete, example of mutable storage is a bank account. In OCaml, record fields can be declared mutable, so that new values can be assigned to them later. Hence, a bank account could be a two-field record, its number, and its balance, where the balance is mutable.
type account = { number : int; mutable balance : float }
let retrieve account requested =
let s = min account.balance requested in
account.balance <- account.balance -. s; s;;
In fact, in OCaml, references are not primitive: they are special cases of mutable records. For instance, one could define:
type 'a ref = { mutable content : 'a }
let ref x = { content = x }
let deref r = r.content
let assign r x = r.content <- x; x
set! in Scheme assigns to a variable. You cannot assign to a variable in OCaml, at all. (So "variables" are not really "variable".) So there is no equivalent.
But OCaml is not a pure functional language. It has mutable data structures. The following things can be assigned to:
Array elements
String elements
Mutable fields of records
Mutable fields of objects
In these situations, the <- syntax is used for assignment.
The ref type mentioned by #jrouquie is a simple, built-in mutable record type that acts as a mutable container of one thing. OCaml also provides ! and := operators for working with refs.
ok, i have this problem here. i was asked to write a function in Scheme, that takes an "environment", and an expression and it returns the value of this expression, for the variable bindings found in the enviroment.
and a definition of a boolean expression is this according to the question below.
edit sorry my question is what does it mean by "it takes an environment" as an argument and what exactly does the function need to do?
evaluate for example "T OR F" and return "F" ???
"<expr> ::= <boolean>
|<variable>
|(not <expr>)
|(or <expr> <expr>)
|(and <expr> <expr>"
An environment is basically a dictionary of variable names to values. So given the environment
var1 = #t
var2 = #f
var3 = #t
and an expression
(or var2 (and T (or var1 var3)))
You would need to substitute the given values of var1, var2, and var3 into the expression, and then evaluate the expression.
Your function will probably be given the environment as some sort of Lisp structure, probably an alist, as one of its parameters.
From what I can determine you have been asked to implement eval.
So you should for starters have:
(define (eval expr env)
... )
where expr can be any of the forms you mention and env would keep the symbols defined (possibly a association list).
The first 2 cases are relatively trivial, the 3rd one, application of the not procedure should also be easy, given not will be in the environment (eg (list (cons 'not not))).
But the harder part lies in the last 2. Both of those are macros, and will require some expansion. The standard definitions/expansions of those should have been given to you. Once expanded, you can simply call eval recursively to evaluate the expanded expression.
Good luck :)
Edit:
Both and and or expands to if, so you will need to implement that too.
By "environment" they probably mean the equivalent of "scope" in other languages. Consider the following C fragment:
if (7 < 100)
{
int j = 2;
if (j < 4)
{
int k = 7, j = 14;
printf("k = %d, j = %d\n", k, j);
}
}
Note that in the outer scope (marked out by the outer set of braces) the only variable is j. In the inner scope there is a new j and a k. So there are three variables here, the outer j, and the inner j and k.
One way of implementing this is to define a scope to be a list of "environments". As you enter a new block, you put another "environment" in your list. When looking up variables by name, you look first in the most recently added "environment". If it isn't found there, you move along the list of environments to the next and look there, and so on.
An "environment" itself is often just a list of pairs, matching up names of variables with values. So it sounds like you are being asked to pass such a list to your function, each pair giving the symbol for a boolean variable and its value. Based on which variables are currently "in scope", you fetch their values out of the environment and use them in the expressions you are evaluating (according to that expression grammar you've been given).
In your case, it sounds like you aren't being asked to worry about which enviroments are in scope. You just have one environment, i.e. one list of pairs.
Sounds like a fair bit of work, good luck!
One reference that might help is:
http://michaux.ca/articles/scheme-from-scratch-bootstrap-v0_9-environments