let rect = new Rectangle(x, y, sprite.Width, sprite.Height)
rect.X <- 888
The second line fails in F#, but in C# the assignment works. I am not sure why.
Rectangle is a struct rather than a class. You can have that line work as you'd expect if you mark the value with mutable:
let mutable rect = new Rectangle(10, 21, 10, 21)
rect.X <- 888
This is actually quite interesting, as F# makes the value-type semantics of structs more visible compared to what C# does.
rect.X <- 888 does not really mutate the field, rather it updates rect with a new value of the struct with the X field modified. So you can imagine it does an equivalent of rect <- { rect with X = 888 }. At that point it's quite clear why the compiler wants to see mutable there.
I wonder why F# designers didn't prohibit assignment syntax for structs and go with something similar to the record syntax. Probably they didn't want to make it too different compared to C#.
As the compiler is probably saying,
A value must be mutable in order to mutate the contents or take the
address of a value type, e.g. 'let mutable x = ...'
In F#, let creates an immutable variable (i.e. a value). The compiler enforces this by not letting you mutate it. You must write let mutable to get an equivalent variable declaration to what you had in C#.
Note that if Rectangle was a reference type, F# wouldn't complain, because you'd be modifying what is referenced by the value, not the value itself. In the case of a value type (like Mono's Rectangle), the identifier bound to the value is the value itself, so you cannot mutate it.
Related
In Dart, looking at the code below, does it 'pass by reference' for list and 'pass by value' for integers? If that's the case, what type of data will be passed by reference/value? If that isn't the case, what's the issue that causes such output?
void main() {
var foo = ['a','b'];
var bar = foo;
bar.add('c');
print(aoo); // [a, b, c]
print(bar); // [a, b, c]
var a = 3;
int b = a;
b += 2;
print(a); // 3
print(b); // 5
}
The question your asking can be answered by looking at the difference between a value and a reference type.
Dart like almost every other programming langue makes a distinction between the two. The reason for this is that you divide memory into the so called stack and the heap. The stack is fast but very limited so it cannot hold that much data. (By the way, if you have too much data stored in the stack you will get a Stack Overflow exception which is where the name of this site comes from ;) ). The heap on the other hand is slower but can hold nearly infinite data.
This is why you have value and reference types. The value types are all your primitive data types (in Dart all the data type that are written small like int, bool, double and so on). Their values are small enough to be stored directly in the stack. On the other hand you have all the other data types that may potentially be much bigger so they cannot be stored in the stack. This is why all the other so called reference types are basically stored in the heap and only an address or a reference is stored in the stack.
So when you are setting the reference type bar to foo you're essentially just copying the storage address from bar to foo. Therefore if you change the data stored under that reference it seems like your changing both values because both have the same reference. In contrast when you say b = a your not transferring the reference but the actual value instead so it is not effected if you make any changes to the original value.
I really hope I could help answering your question :)
In Dart, all type are reference types. All parameters are passed by value. The "value" of a reference type is its reference. (That's why it's possible to have two variables containing the "same object" - there is only one object, but both variables contain references to that object). You never ever make a copy of an object just by passing the reference around.
Dart does not have "pass by reference" where you pass a variable as an argument (so the called function can change the value bound to the variable, like C#'s ref parameters).
Dart does not have primitive types, at all. However (big caveat), numbers are always (pretending to be) canonicalized, so there is only ever one 1 object in the program. You can't create a different 1 object. In a way it acts similarly to other languages' primitive types, but it isn't one. You can use int as a type argument to List<int>, unlike in Java where you need to do List<Integer>, you can ask about the identity of an int like identical(1, 2), and you can call methods on integers like 1.hashCode.
If you want to clone or copy a list
var foo = ['a', 'b'];
var bar = [...foo];
bar.add('c');
print(bar); // [a, b, c]
print(foo); // [a, b]
var bar_two = []; //or init an empty list
bar_two.addAll([...bar]);
print(bar_two); // [a, b, c]
Reference link
Clone a List, Map or Set in Dart
This is the question about the earlier Persistence class that I was trying to expose as an enumerator. I realized that I need to pass by reference really to change the value of of the object that I am trying to populate. I guess I am going about this in a C++ way (As most may have guessed I am an F# beginner). However, I want to be as efficient in terms of memory foot print as I can. Ideally I would like to reuse the same object over and over again when I read from a file.
I am having a problem with this code where it does not allow me to pass by reference in the call to the function serialize. I am again reproducing the code here. I thank you in advance for your help.
The error I get:
error FS0001: This expression was expected to have type byref<'T> but here has type 'T
If I change the call to serialize(& current_, reader_) I get the following error:
persistence.fs(71,6): error FS0437: A type would store a byref typed value. This is not permitted by Common IL.
persistence.fs(100,29): error FS0412: A type instantiation involves a byref type. This is not permitted by the rules of Common IL.
persistence.fs(100,30): error FS0423: The address of the field current_ cannot be used at this point
The CODE:
type BinaryPersistenceIn<'T when 'T: (new : unit -> 'T)>(fn: string, serializer: ('T byref * BinaryReader) -> unit) =
let stream_ = File.Open(fn, FileMode.Open, FileAccess.Read)
let reader_ = new BinaryReader(stream_)
let mutable current_ = new 'T()
let eof() =
stream_.Position = stream_.Length
interface IEnumerator<'T> with
member this.Current
with get() = current_
member this.Dispose() =
stream_.Close()
reader_.Close()
interface System.Collections.IEnumerator with
member this.Current
with get() = current_ :> obj
member this.Reset() =
stream_.Seek((int64) 0., SeekOrigin.Begin) |> ignore
member this.MoveNext() =
let mutable ret = eof()
if stream_.CanRead && ret then
serializer( current_, reader_)
ret
You can circumvent this by introducing a mutable local, passing it to serialize, and then assigning back to current_:
member this.MoveNext() =
let mutable ret = eof()
if stream_.CanRead && ret then
let mutable deserialized = Unchecked.defaultof<_>
serializer( &deserialized, reader_)
current_ <- deserialized
ret
But now this is becoming really, really unsettling. Notice the use of Unchecked.defaultof<_>? There is no other way to initialize a value of unknown type, and it's called "unchecked" for a reason: the compiler can't guarantee safety of this code.
I strongly advise that you explore other ways of achieving your initial goal, such as using a seq computation expression instead, as I have suggested in your other question.
With respect to memory footprint, let's analyze the sequence option:
You have an instance of the seq. That's going to be some class implementing IEnumerable<'T>. This one will be held until you no longer need the seq, i.e. not reallocated each time.
You hold a Stream as part of the seq, with the same lifetime.
You hold a BinaryReader as part of the seq, with the same lifetime.
eof : unit -> bool is a compiler-generated function class as part of the seq, with the same lifetime.
The loop will use a bool for the while loop and the if condition. Both of which are stack-allocated structs and needed for the branching logic.
And finally, you yield an instance that you already got from the serializer.
Conceptually, that's as little memory consumption as you can have for a lazily evaluated seq. Once an element is consumed, it can be garbage collected. Multiple evaluations will do the same thing again.
The only thing you can actually play with, is what the serializer returns.
If you have your serializer return a struct, it is copied and stack-allocated. And it should not be mutable. Mutable structs discouraged. Why are mutable structs “evil”?
Structs are good with respect to the garbage collector as they avoid garbage collection. But they are typically to be used with very small objects, in the order of say 16-24 bytes max.
Classes are heap-allocated and are passed by reference always. So if your serializer returns a class, say a string, then you just pass that around by reference and overhead of copying will be very small as you only ever copy the reference, not the content.
If you want your serializer side-effecting, i.e. overwriting the same object (class, i.e. reference type is to be used for this), then the whole approach of IEnumerable<'T> and consequently seq is wrong. IEnumerables always give you new objects as result and should never modify any pre-existing object. The only state with them should be the information, at what place in the enumeration they are.
So if you need a side-effecting version, you could do something like (pseudo-code).
let readAndOverwrite stream target =
let position = // do something here to know the state
fun target ->
target.MyProp1 <- stream.ReadInt()
target.MyProp2 <- stream.ReadFloat()
Passing as byref does not seem very reasonable to me, as you then anyway allocate and garbage collect the object. So you can just as well do that in an immutable way. What you can do, is just modifying properties on your object instead.
Consider below struct:
typedef struct _Index {
NSInteger category;
NSInteger item;
} Index;
If I use this struct as a property:
#property (nonatomic, assign) Index aIndex;
When I access it without any initialization right after a view controller alloc init, LLDB print it as:
(lldb) po vc.aIndex
(category = 0, item = 0)
(lldb) po &_aIndex
0x000000014e2bcf70
I am a little confused, the struct already has valid memory address, even before I want to allocate one. Does Objective-C initialize struct automatically? If it is a NSObject, I have to do alloc init to get a valid object, but for C struct, I get a valid struct even before I tried to initialize it.
Could somebody explains, and is it ok like this, not manually initializing it?
To answer the subquestion, why you cannot assign to a structure component returned from a getter:
(As a motivation this is, because I have read this Q several times.)
A. This has nothing to do with Cbjective-C. It is a behavior stated in the C standard. You can check it for simple C code:
NSMakeSize( 1.0, 2.0 ).width = 3.0; // Error
B. No, it is not an improvement of the compiler. If it would be so, a warning would be the result, not an error. A compiler developer does not have the liberty to decide what an error is. (There are some cases, in which they have the liberty, but this are explicitly mentioned.)
C. The reason for this error is quite easy:
An assignment to the expression
NSMakeSize( 1.0, 2.0 ).width
would be legal, if that expression is a l-value. A . operator's result is an l-value, if the structure is an l-value:
A postfix expression followed by the . operator and an identifier designates a member of a structure or union object. The value is that of the named member,82) and is an lvalue if the first expression is an lvalue.
ISO/IEC 9899:TC3, 6.5.2.3
Therefore it would be assignable, if the expression
NSMakeSize( 1.0, 2.0 )
is an l-value. It is not. The reason is a little bit more complex. To understand that you have to know the links between ., -> and &:
In contrast to ., -> always is an l-value.
A postfix expression followed by the -> operator and an identifier designates a member of a structure or union object. The value is that of the named member of the object to which the first expression points, and is an lvalue. 83)
Therefore - that is what footnote 83 explains – ->, &, and . has a link:
If you can calculate the address of a structure S having a component C with the & operator, the expression (&S)->C is equivalent to S.C. This requires that you can calculate the address of S. But you can never do that with a return value, even it is a simple integer …
int f(void)
{
return 1;
}
f()=5; // Error
… or a pointer …
int *f(void)
{
return NULL;
}
f()=NULL; // Error
You always get the same error: It is not assignable. Because it is a r-value. This is obvious, because it is not clear,
a) whether the way the compiler returns a value, esp. whether he does it in address space.
b) when the time the life time of the returned value is over
Going back to the structure that means that the return value is a r-value. Therefore the result of the . operator on that is a r-value. You are not allowed to assign a value to a r-value.
D. The solution
There is a solution to assign to a "returned structure". One might decide, whether it is good or not. Since -> always is an l-value, you can return a pointer to the structure. Dereferencing this pointer with the -> operator has always an l-value as result, so you can assign a value to it:
// obj.aIndex returns a pointer
obj.aIndex->category = 1;
You do not need #public for that. (What really is a bad idea.)
The semantics of the property are to copy the struct, so it doesn't need to be allocated and initialized like an Objective-C object would. It's given its own space like a primitive type is.
You will need to be careful updating it, as this won't work:
obj.aIndex.category = 1;
Instead you will need to do this:
Index index = obj.aIndex;
index.category = 1;
obj.aIndex = index;
This is because the property getter will return a copy of the struct and not a reference to it (the first snippet is like the second snippet, without the last line that assigns the copy back to the object).
So you might be better off making it a first class object, depending on how it will be used.
The first definition below produces the warning in the title when compiled with f# 3.0 and the warning level set to 5. The second definition compiles cleanly. I wondered if someone could please explain just what the compiler worries I might accidentally mutate, or how would splitting the expression with a let clause help avoid that. Many thanks.
let ticks_with_warning () : int64 =
System.DateTime.Now.Ticks
let ticks_clean () : int64 =
let t = System.DateTime.Now
t.Ticks
I cannot really explain why the compiler emits this warning in your particular case - I agree with #ildjarn that you can safely ignore it, because the compiler is probably just being overly cautious.
However, I can give you an example where the warning might actually give you a useful hint that something might not go as you would expect. If we had a mutable struct like this:
[<Struct>]
type Test =
val mutable ticks : int64
member x.Inc() = x.ticks <- x.ticks + 1L
new (init) = { ticks = init }
Now, the Inc method mutates the struct (and you can also access the mutable field ticks). We can try writing a function that creates a Test value and mutates it:
let foo () =
let t = Test(1L)
t.Inc() // Warning: The value has been copied to ensure the original is not mutated
t
We did not mark the local value t as mutable, so the compiler tries to make sure the value is not mutated when we call Inc. It does not know whether Inc mutates the value or not, so the only safe thing is to create a copy - and thus foo returns the value Test(1L).
If we mark t as mutable, then the compiler does not have to worry about mutating it as a result of a call and so it does not give the warning (and the function returns Test(2L)):
let foo () =
let mutable t = Test(1L)
t.Inc()
t
I'm not really sure what is causing the warning in your example though. Perhaps the compiler thinks (as a result of some intermediate representation) that Ticks operation could mutate the left-hand-side value (System.DateTime.Now and t respectively) and it wants to prevent that.
The odd thing is that if you write your own DateTime struct in F#, you get a warning in both cases unless you mark the variable t as mutable (which is what I'd expect), but the behaviour with standard DateTime is different. So perhaps the compiler knows something about the standard type that I'm missing...
Any way to declare a new variable in F# without assigning a value to it?
See Aidan's comment.
If you insist, you can do this:
let mutable x = Unchecked.defaultof<int>
This will assign the absolute zero value (0 for numeric types, null for reference types, struct-zero for value types).
It would be interesting to know why the author needs this in F# (simple example of intended use would suffice).
But I guess one of the common cases when you may use uninitialised variable in C# is when you call a function with out parameter:
TResult Foo<TKey, TResult>(IDictionary<TKey, TResult> dictionary, TKey key)
{
TResult value;
if (dictionary.TryGetValue(key, out value))
{
return value;
}
else
{
throw new ApplicationException("Not found");
}
}
Luckily in F# you can handle this situation using much nicer syntax:
let foo (dict : IDictionary<_,_>) key =
match dict.TryGetValue(key) with
| (true, value) -> value
| (false, _) -> raise <| ApplicationException("Not Found")
You can also use explicit field syntax:
type T =
val mutable x : int
I agree with everyone who has said "don't do it". However, if you are convinced that you are in a case where it really is necessary, you can do this:
let mutable naughty : int option = None
...then later to assign a value.
naughty <- Some(1)
But bear in mind that everyone who has said 'change your approach instead' is probably right. I code in F# full time and I've never had to declare an unassigned 'variable'.
Another point: although you say it wasn't your choice to use F#, I predict you'll soon consider yourself lucky to be using it!
F# variables are by default immutable, so you can't assign a value later. Therefore declaring them without an initial value makes them quite useless, and as such there is no mechanism to do so.
Arguably, a mutable variable declaration could be declared without an initial value and still be useful (it could acquire an initial default like C# variables do), but F#'s syntax does not support this. I would guess this is for consistency and because mutable variable slots are not idiomatic F# so there's little incentive to make special cases to support them.