struct Data {
public int x;
}
void change_x(Data data) {
data.x = 123;
}
Data a = Data();
change_x(a);
print("%d", a.x); // 0
but the document says:
when a struct type instance is passed to a method, a copy is not made. Instead a reference to the instance is passed.
- in https://wiki.gnome.org/Projects/Vala/Manual/Types
What is wrong?
Structs in Vala are implemented as copy on assignment and pass by reference. So you can think of your example as copying the struct because it is being assigned to a parameter in a function and then that copy is passed by reference. This is what is happening behind the scenes in the generated C code, but from the Vala side it means a struct is a value type. Only when interfacing with a C library is it useful to know a copy of the struct is passed by reference. The quote from the manual refers to struct methods, but before we look at that in detail let's understand a bit more about value and reference types.
Vala, like Java, C# and many other languages, has two kinds of data types: value types and reference types.
Value Types are Passed by Value
When a value type is passed as an argument to a function or a method then the value is passed as the argument, but it is a copy of the value. If the function or method goes on to modify the parameter it received this will not change the value in the calling code. The code is encapsulated.
The following example:
void main () {
int a = 23;
print ("Initial value: %i\n", a);
modify_example (a);
print ("Final value: %i\n", a);
}
void modify_example (int x) {
x += 100;
}
produces:
Initial value: 23
Final value: 23
Although the value is modified in the function it does not also modify the value from the calling code.
Value Types Can be Passed by Reference
Instead of passing the value to a function or a method the use of the ref keyword will pass a reference to the value. This creates an alias for the calling value. The result is two identifiers for the same memory location.
By just adding the ref keyword the following example:
void main () {
int a = 23;
print ("Initial value: %i\n", a);
modify_example (ref a);
print ("Final value: %i\n", a);
}
void modify_example (ref int x) {
x += 100;
}
now produces:
Initial value: 23
Final value: 123
By calling modify_example () the side effect is to also change the value in the calling code. The use of ref makes this explicit and can be used as a way for a function to return multiple values, but in this example it would be clearer to return the modified value instead of passing by reference.
Reference Types are Always Passed by Reference
Objects are reference types. This example doesn't use an explicit ref, but the value is changed in the calling code:
void main () {
var a = new ExampleReferenceType (23);
print ("Initial value: %i\n", a.value);
modify_example (a);
print ("Final value: %i\n", a.value);
}
class ExampleReferenceType {
public int value;
public ExampleReferenceType (int default = 0) {
this.value = default;
}
}
void modify_example (ExampleReferenceType x) {
x.value += 100;
}
This produces:
Initial value: 23
Final value: 123
Objects modified in this way can cause problems when tracking down a bug. That is an advantages of making value objects immutable. This would be done by only setting the value in the constructor, making all fields private and only using a property to get the value, but not set it.
Structs as Value Types
The following code:
void main () {
ExampleStruct a = { 23 };
print ("Initial value: %i\n", a.value);
modify_example (a);
print ("Final value: %i\n", a.value);
}
private struct ExampleStruct {
public int value;
}
void modify_example (ExampleStruct x) {
x.value += 100;
}
is similar to your code and produces:
Initial value: 23
Final value: 23
This is the same behaviour in Vala as the other value types, but if you look at the C code by using the --ccode switch with valac you will see the struct is copied and passed by reference. This is relevant when you need to understand how Vala maintains the C ABI (Application Binary Interface).
Struct Methods
The reference you make to the manual may not be clear, but I think it relates to methods within structs. If modify_example is moved inside the struct definition:
void main () {
ExampleStruct a = { 23 };
print ("Initial value: %i\n", a.value);
a.modify_example ();
print ("Final value: %i\n", a.value);
}
private struct ExampleStruct {
public int value;
public void modify_example () {
this.value += 100;
}
}
this now produces:
Initial value: 23
Final value: 123
The method now operates on the instance.
[SimpleType] Structs
The section from the manual you quote also states in the next sentence:
This behaviour can be changed by declaring the struct to be a simple
type.
So for completeness here is the final example:
void main () {
ExampleStruct a = { 23 };
print ("Initial value: %i\n", a.value);
a.modify_example ();
print ("Final value: %i\n", a.value);
}
[SimpleType]
private struct ExampleStruct {
public int value;
public void modify_example () {
this.value += 100;
}
}
and this produces:
Initial value: 23
Final value: 23
Although the method is still defined within the struct the instance is passed by value instead of reference.
Simple type structs are how the fundamental value types are defined in Vala, for example int and int64. If you want a struct method defined that acts on a simple type struct instance then the method will have to be defined to return a new instance containing the modified value.
Conclusion
Structs are value types in Vala, but it is useful to know how they are implemented to understand compatibility with the C ABI. In your example the struct behaves as a value type, but is copied and passed by reference in terms of the C ABI. The quote seems most relevant to methods defined within structs.
I think the quoted text you are refering to is either outdated or was wrong to begin with.
You have to use ref (or out) if you want it to be passed by reference (hence the name ref).
struct Data {
public int x;
}
void change_x (ref Data data) {
data.x = 123;
}
int main () {
Data a = Data ();
change_x (ref a);
print ("%d\n", a.x);
return 0;
}
Related
I created a struct with a reference to a vector and I'm having problems assigning to it after I created an array of structs.
This is my struct:
struct name{
std::vector<Student> &A;
int a;
int b;
};
In my main, I have created a vector of class type, Student, and I have assigned values to the vector, which I called StudentVector. I'm trying to declare an array of struct name that contains a reference to my vector, StudentVector:
void main(){
std::vector <Student> StudentVector;
....
....
....
name data[5];
for (int i=0;i<5;i++){
data[i].A = StudentVector;
}
When I do this, it compiles, but I get a segmentation fault when I run my code.
Thank you in advance for the help!
It should not compile, because there is no way how to initialize the reference 'A'. If you really need to do it this way, replace the reference with a pointer:
struct name {
std::vector<Student> *A;
int a;
int b;
};
std::vector<Student> StudentVector;
for (int i = 0; i < 5; i++) {
data[i].A = &StudentVector;
}
But it would be wise to avoid it completely.
I'm working with the CoreFoundation framework on OS X, but I don't know how to map this function in Rust:
void CFRunLoopPerformBlock(CFRunLoopRef fl, CFTypeRef mode, void (^block)(void));
The last parameter is void(^block)(void) — how can I create arguments of this type?
Short, probably helpful answer: there's the block crate, which looks like it might do the job.
Short, unhelpful answer: Insofar as I am aware, Rust doesn't have any support for Apple's block extension. There is no equivalent Rust type, assuming you want to call an API that expects a block.
Longer, marginally less unhelpful answer: From what I can gather from some Clang documentation on the Apple Block ABI, void(^)(void) would be the same size as a regular pointer.
As such, my advice is as follows: treat blocks as opaque, pointer-sized values. To invoke one, write a function in C which calls it for you.
The following is untested (I don't have a Mac), but should at least get you going in the right direction. Also, I'm marking this community wiki so anyone who can test it can fix it if need-be.
In Rust:
// These are the "raw" representations involved. I'm not using std::raw
// because that's not yet stabilised.
#[deriving(Copy, Clone)]
struct AppleBlock(*const ());
#[deriving(Copy, Clone)]
struct RustClosure(*const(), *const());
// Functions that we need to be written in C:
extern "C" {
fn rust_closure_to_block(closure_blob: RustClosure) -> AppleBlock;
fn block_release(block_blob: AppleBlock);
}
// The function that the C code will need. Note that this is *specific* to
// FnMut() closures. If you wanted to generalise this, you could write a
// generic version and pass a pointer to that to `rust_closure_to_block`.
extern "C" fn call_rust_closure(closure_blob: RustClosure) {
let closure_ref: &FnMut() = unsafe { mem::transmute(closure_blob) };
closure_ref();
}
// This is what you call in order to *temporarily* turn a closure into a
// block. So, you'd use it as:
//
// with_closure_as_block(
// || do_stuff(),
// |block| CFRunLoopPerformBlock(fl, mode, block)
// );
fn with_closure_as_block<C, B, R>(closure: C, body: B) -> R
where C: FnMut(), B: FnOnce(block_blob) -> R {
let closure_ref: &FnMut() = &closure;
let closure_blob: RustClosure = unsafe { mem::transmute(closure_ref) };
let block_blob = unsafe { rust_closure_to_block(closure_blob) };
let r = body(block_blob);
unsafe { block_release(block_blob) };
r
}
In C:
typedef struct AppleBlock {
void *ptr;
} AppleBlock;
typedef struct RustClosure {
void *ptr;
void *vt;
} RustClosure;
void call_rust_closure(RustClosure closure_blob);
AppleBlock rust_closure_to_block(RustClosure closure_blob) {
return (AppleBlock)Block_copy(^() {
call_rust_closure(closure_blob);
});
}
// I'm not using Block_release directly because I don't know if or how
// blocks change name mangling or calling. You might be able to just
// use Block_release directly from Rust.
void block_release(AppleBlock block) {
Block_release((void (^)(void))block);
}
struct A {}
func (a *A) BName(id int) string {
return a.Name
}
struct B {
*A
Name string
}
func main() {
b := &B{Name: "abc"}
fmt.Println(b.Name)
}
the code failure, I want know how to write code to achieve, A.BName can access B struct attribute Name
This is not possible. struct A does not know anything about the types it is embedded into. Think about it, A can be embedded into any other struct, so how could you know ahead of time the type of the struct that A is embedded into.
If you want to do this, you need to place a reference to B, the outer structure into A.
type A struct {
*B
}
func (a *A) PrintName() string { return a.B.Name }
type B struct {
A // no need to use a pointer here
Name string
}
var b B
b.A.B = &b
fmt.Println(b.PrintName())
A accessing B reminds me of a is-a relationship, where A "is-a" B.
The article "Is Go an Object Oriented language?" does note that there is no true subtyping in Go:
if it was truly subtyping then the anonymous field would cause the outer type to become the inner type. In Go this is simply not the case. The two types remain distinct.
The anonymous fields are still accessible as if they were embedded
Example:
package main
type A struct{
// doesn't know anything about B
}
type B struct {
A //B is-a A
}
func (a *A) f() { fmt.Println("A.f") }
func (b *B) f() { fmt.Println("B.f") }
func save(A) {
//do something
}
func main() {
b := B
save(&b) //OOOPS! b IS NOT A
b.f() // B.f()
b.A.f() // A.f()
}
One of the issues with multiple inheritance is that languages are often non obvious and sometimes even ambiguous as to which methods are used when identical methods exist on more than one parent class.
With Go you can always access the individual methods through a property which has the same name as the type.
In reality when you are using Anonymous fields, Go is creating an accessor with the same name as your type.
That is what "b.A" is: an accessor to an anonymous field..
How can I create a garbage-collected copy of a struct that's on the stack?
Coming from a C++ background, my first guess would be a copy constructor like the one below, but it doesn't seem very idiomatic for D, and I haven't seen one in any of the D projects I've taken a look at.
struct Foo {
immutable int bar;
this(int b) { bar = b; }
// A C++-style copy constructor works but doesn't seem idiomatic.
this(ref const Foo f) { bar = f.bar; }
}
void main()
{
// We initialize a Foo on the stack
auto f = Foo(42);
// Now I want to get a heap copy of its member. How?
// A C++-style copy constructor works but doesn't seem idiomatic.
Foo* f1 = new Foo(f);
}
Your example is overly complicated and doesn't even compile, but essentially, it sounds like what you want to be able to do is something like
struct Foo
{
int i;
}
void main()
{
auto f = Foo(5);
auto g = new Foo(f);
}
What you can do without any special constructors is
void main()
{
auto f = Foo(5);
auto g = new Foo;
*g = f;
}
but obviously that's more steps than you probably want. The normal "copy constructor" for D is a postblit constructor, which is declared as this(this) {...}, but that's not required for Foo as it's declared here (since all of its members are value types), and it doesn't help with allocating a struct on the heap anyway - just with copying a struct. Arguably
auto f = Foo(5);
auto g = new Foo(f);
should just work, but at the moment, it doesn't, and there is unfortunately, no support in the language for defining it for you. So, unfortunately, I think that you're currently forced to do something akin to what you're trying to avoid. e.g.
struct Foo
{
int i;
this(int j)
{
i = j;
}
this(Foo rhs)
{
this = rhs;
}
}
void main()
{
auto f = Foo(5);
auto g = new Foo(f);
}
However, I just opened an enhancement request for making it so that new Foo(foo) will just work, and with the next release of dmd (2.066) we're going to get universal construction for primitive types (e.g. new int(5) will now work), so I think that there's a very good argument for this just working as well.
For now though, you're going to have to provide an extra constructor to get this to work.
[s].ptr will copy the struct s to the heap, and get a pointer to it.
I have this struct:
struct foo {
int a;
union {
struct {
int b;
struct bar
{
int c;
int d;
} *aBar;
} in;
} u;
};
How I need to declare a variable of type bar, in Visual C++ ?
When you declare an structure like this:
struct
{
int b;
} in;
You are actually creating an object with name in, having unnamed-data type. This data-type would be named internally by compiler, and depends on compiler. The style given above does not declare in to be a type, but a variable!
If you want to make it a type, use either of given approaches:
// Approach 1
struct in{...};
// Approach 2
typedef struct {..} in; // in is now a type, because of `typedef`
If you have compiler that supports C++0x, and specifically type decltype keyword, you can use it against the first style (which makes in a variable). Example:
decltype(in) in_var;
in_var.b = 10;
Thanks Ajay, I solved that way:
foo *k;
decltype(k->u.in.aBar) j;
j->c = 1;
j->d = 1;