What is the difference between these two types of data struct? - struct

Can anyone tell me what the difference between these two types of data structures is? The first one uses TAG "worker". In the second one I declared the names in the data structure itself "rober" and "zzymon". As for me, the first one is more practical to use...
// FIRST structure TAG**
struct worker
{
int age1;
char *hair_color1;
};
struct worker grzegorz;
grzegorz.age1 = 15;
grzegorz.hair_color1 = "gray";
struct worker krzys;
krzys.age1 = 26;
krzys.hair_color1 = "white";
// SECOND structure variables struct type**
struct
{
int age2;
char *hair_color2;
}
robert, szymon;
robert.age2 = 12;
robert.hair_color2 = "blond";
szymon.age2 = 14;
szymon.hair_color2 = "gray";

The first one defines a struct type struct worker and then later defines two instances of that struct type grzgorz and krzys.
The second one defines two instances of an anonymous struct type called robert and szymon
In both cases, you get two objects of the same struct type you can do things with. In the first case, that struct type also has a name, so you can later define other things with the same type (or pointers to that type, etc), while in the second case you cannot, as the struct type is anonymous.

Related

Variadic generic trait paramterised on same type in Rust

I would broadly like to write something like this:
pub struct Example<..T> {...}
That is, parametrise Example over any number of type T. This is discussed in an RFC, but this seems to be quite stale.
I know that we can have variadic functions by using c_variadic. Is there any way to expand this to structs?
Edit to include more concrete example:
What I am trying to do is (may not be valid Rust, but just an example):
// `a` and `b` are some structs that communicate via channels
// Label is some label we can match on
// Continuation is a trait
let options = vec![(label1, cont1), (label2, cont2)...];
let a = Offer<...(Label, Continuation)>::new();
let b = Pick<Label>::new();
// offer and pick are just some functions that communicate
// the choice via channels
// The important part being that offer and pick would be parametrised
// over <..(Label, Continuation)>
let picked = a.offer(options);
let picked = b.pick(label1);
Perhaps you want a const size parameter:
struct Offer<T, const U: usize> {
contents: [T; U]
}
This can represent a list of any size. All items must be of the same type though but in your example this seems to be the case.

How to handle generic types with different concrete types in rust efficiently?

The main goal is to implement a computation graph, that handles nodes with values and nodes with operators (think of simple arithmetic operators like add, subtract, multiply etc..). An operator node can take up to two value nodes, and "produces" a resulting value node.
Up to now, I'm using an enum to differentiate between a value and operator node:
pub enum Node<'a, T> where T : Copy + Clone {
Value(ValueNode<'a, T>),
Operator(OperatorNode)
}
pub struct ValueNode<'a, T> {
id: usize,
value_object : &'a dyn ValueType<T>
}
Update: Node::Value contains a struct, which itself contains a reference to a trait object ValueType, which is being implemented by a variety of concrete types.
But here comes the problem. During compililation, the generic types will be elided, and replaced by the actual types. The generic type T is also being propagated throughout the computation graph (obviously):
pub struct ComputationGraph<T> where T : Copy + Clone {
nodes: Vec<Node<T>>
}
This actually restricts the usage of ComputeGraph to one specific ValueType.
Furthermore the generic type T cannot be Sized, since a value node can be an opqaue type handled by a different backend not available through rust (think of C opqaue types made available through FFI).
One possible solution to this problem would be to introduce an additional enum type, that "mirrors" the concrete implementation of the valuetype trait mentioned above. this approach would be similiar, that enum dispatch does.
Is there anything I haven't thought of to use multiple implementations of ValueType?
update:
What i want to achive is following code:
pub struct Scalar<T> where T : Copy + Clone{
data : T
}
fn main() {
let cg = ComputeGraph::new();
// a new scalar type. doesn't have to be a tuple struct
let a = Scalar::new::<f32>(1.0);
let b_size = 32;
let b = Container::new::<opaque_type>(32);
let op = OperatorAdd::new();
// cg.insert_operator_node constructs four nodes: 3 value nodes
// and one operator nodes internally.
let result = cg.insert_operator_node::<Container>(&op, &a, &b);
}
update
ValueType<T> looks like this
pub trait ValueType<T> {
fn get_size(&self) -> usize;
fn get_value(&self) -> T;
}
update
To further increase the clarity of my question think of a small BLAS library backed by OpenCL. The memory management and device interaction shall be transparent to the user. A Matrix type allocates space on an OpenCL device with types as a primitive type buffer, and the appropriate call will return a pointer to that specific region of memory. Think of an operation that will scale the matrix by a scalar type, that is being represented by a primitive value. Both the (pointer to the) buffer and the scalar can be passed to a kernel function. Going back to the ComputeGraph, it seems obvious, that all BLAS operations form some type of computational graph, which can be reduced to a linear list of instructions ( think here of setting kernel arguments, allocating buffers, enqueue the kernel, storing the result, etc... ). Having said all that, a computation graph needs to be able to store value nodes with a variety of types.
As always the answer to the problem posed in the question is obvious. The graph expects one generic type (with trait bounds). Using an enum to "cluster" various subtypes was the solution, as already sketched out in the question.
An example to illustrate the solution. Consider following "subtypes":
struct Buffer<T> {
// fields
}
struct Scalar<T> {
// fields
}
struct Kernel {
// fields
}
The value containing types can be packed into an enum:
enum MemType {
Buffer(Buffer<f32>);
Scalar(Scalar<f32>);
// more enum variants ..
}
Now MemType and Kernel can now be packed in an enum as well
enum Node {
Value(MemType);
Operator(Kernel);
}
Node can now be used as the main type for nodes/vertices inside the graph. The solution might not be very elegant, but it does the trick for now. Maybe some code restructuring might be done in the future.

Initialize two struct members with a function that returns a tuple in Rust

So I have a function that returns a tuple of 2 values, and I want to assign these values to two different members of a struct. Is there a way to do this without having to call the function twice and extract each value individually?
I'm thinking something like:
let mut my_struct : MyStruct = MyStruct {
(member1, member2): function_that_returns_tuple()
}
Currently I am calling the function on two temporary variables and then moving them to the struct members but I'm wondering if there's a way to do it directly in the initialization.
I believe that your existing approach is the correct one. If you name the variables as the struct members, you can avoid the explicit member: value syntax:
let (member1, member2) = function_that_returns_tuple();
MyStruct { member1, member2, }

What are the differences between the multiple ways to create zero-sized structs?

I found four different ways to create a struct with no data:
struct A{} // empty struct / empty braced struct
struct B(); // empty tuple struct
struct C(()); // unit-valued tuple struct
struct D; // unit struct
(I'm leaving arbitrarily nested tuples that contain only ()s and single-variant enum declarations out of the question, as I understand why those shouldn't be used).
What are the differences between these four declarations? Would I use them for specific purposes, or are they interchangeable?
The book and the reference were surprisingly unhelpful. I did find this accepted RFC (clarified_adt_kinds) which goes into the differences a bit, namely that the unit struct also declares a constant value D and that the tuple structs also declare constructors B() and C(_: ()). However it doesn't offer a design guideline on why to use which.
My guess would be that when I export them with pub, there are differences in which kinds can actually be constructed outside of my module, but I found no conclusive documentation about that.
There are only two functional differences between these four definitions (and a fifth possibility I'll mention in a minute):
Syntax (the most obvious). mcarton's answer goes into more detail.
When the struct is marked pub, whether its constructor (also called struct literal syntax) is usable outside the module it's defined in.
The only one of your examples that is not directly constructible from outside the current module is C. If you try to do this, you will get an error:
mod stuff {
pub struct C(());
}
let _c = stuff::C(()); // error[E0603]: tuple struct `C` is private
This happens because the field is not marked pub; if you declare C as pub struct C(pub ()), the error goes away.
There's another possibility you didn't mention that gives a marginally more descriptive error message: a normal struct, with a zero-sized non-pub member.
mod stuff {
pub struct E {
_dummy: (),
}
}
let _e = stuff::E { _dummy: () }; // error[E0451]: field `_dummy` of struct `main::stuff::E` is private
(Again, you can make the _dummy field available outside of the module by declaring it with pub.)
Since E's constructor is only usable inside the stuff module, stuff has exclusive control over when and how values of E are created. Many structs in the standard library take advantage of this, like Box (to take an obvious example). Zero-sized types work in exactly the same way; in fact, from outside the module it's defined in, the only way you would know that an opaque type is zero-sized is by calling mem::size_of.
See also
What is an idiomatic way to create a zero-sized struct that can't be instantiated outside its crate?
Why define a struct with single private field of unit type?
struct D; // unit struct
This is the usual way for people to write a zero-sized struct.
struct A{} // empty struct / empty braced struct
struct B(); // empty tuple struct
These are just special cases of basic struct and tuple struct which happen to have no parameters. RFC 1506 explains the rational to allow those (they didn't used to):
Permit tuple structs and tuple variants with 0 fields. This restriction is artificial and can be lifted trivially. Macro writers dealing with tuple structs/variants will be happy to get rid of this one special case.
As such, they could easily be generated by macros, but people will rarely write those on their own.
struct C(()); // unit-valued tuple struct
This is another special case of tuple struct. In Rust, () is a type just like any other type, so struct C(()); isn't much different from struct E(u32);. While the type itself isn't very useful, forbidding it would make yet another special case that would need to be handled in macros or generics (struct F<T>(T) can of course be instantiated as F<()>).
Note that there are many other ways to have empty types in Rust. Eg. it is possible to have a function return Result<(), !> to indicate that it doesn't produce a value, and cannot fail. While you might think that returning () in that case would be better, you might have to do that if you implement a trait that dictates you to return Result<T, E> but lets you choose T = () and E = !.

GCD dispatch_set_target_queue function's 1st parameter type

The function prototype is this:
void dispatch_set_target_queue(
dispatch_object_t object,
dispatch_queue_t queue);
typedef union {
struct dispatch_object_s *_do;
struct dispatch_continuation_s *_dc;
struct dispatch_queue_s *_dq;
struct dispatch_queue_attr_s *_dqa;
struct dispatch_group_s *_dg;
struct dispatch_source_s *_ds;
struct dispatch_source_attr_s *_dsa;
struct dispatch_semaphore_s *_dsema;
struct dispatch_data_s *_ddata;
struct dispatch_io_s *_dchannel;
struct dispatch_operation_s *_doperation;
struct dispatch_fld_s *_dfld;
} dispatch_object_t __attribute__((transparent_union));
I am confused why below code could pass compiling???
dispatch_queue_t queueA = dispatch_queue_create("com.effectiveobjectivec.queueA", NULL);
dispatch_queue_t queueB = dispatch_queue_create("com.effectiveobjectivec.queueB", NULL);
dispatch_set_target_queue(queueB, queueA); // will set queueA as queueB's target
I don't see any field in dispatch_object_t Union is a dispatch_queue_t, so how can queueB argument cause no compile errors?
Also. I wonder what "struct dispatch_object_s *_do;" field is? What is "struct dispatch_queue_s *_dq;"?
You can think of dispatch_object_t as the "base class" of all the dispatch object types.
In "plain" C this uses the transparent union GCC extension, which essentially allows all pointer types in the union to be treated interchangeably with the union type when used as a function argument.
the macro below the block you quoted from dispatch/object.h explains the connection with dispatch_queue_t:
#define DISPATCH_DECL(name) typedef struct name##_s *name##_t
and then later on in dispatch/queue.h
DISPATCH_DECL(dispatch_queue);
i.e. dispatch_queue_t matches the _dq member of the transparent union and hence is a valid type to pass to the dispatch_object_t argument of dispatch_set_target_queue.
FWIW in Objective-C and C++ the dispatch_object_t superclass relationship is expressed using the respective object type system, c.f. the other sections in the dispatch_object_t area of dispatch/object.h.

Resources