Why can I access the attribute of a specific struct when it's stored in a collection of abstract types? - struct

abstract type Elf end
struct LightElf <: Elf
name::String
life::Int32
end
struct DarkElf <: Elf
name::String
life::Int32
# This attribute is only in DarkElf.
enchantment::Int32
end
amber = LightElf("Amber",100)
charles = DarkElf("Charles",20,45)
elves = Elf[]
push!(elves,amber,charles)
charles = DarkElf("Charles",20,45)
println(elves[2].enchantment)
> 45
Why can I access the enchantment field from charles when it's being stored in an array of abstract Elf objects?
In a language like C# or Java, a parent would not know about any attributes specific to that sub class. Obviously, we don't have abstract classes, so we don't know what attributes will make a generic Elf. I guess you could ask, how does Julia know about the attributes that are in a struct?

The answer here is that Julia is a fundamentally dynamic language, while languages like C# and Java are fundamentally static. In Julia (and most dynamic languages) variables don't have a type. Objects do. When you take elves[2] in a static language, you get a variable of type Elf. When you do it is Julia, you get a DarkElf.

Related

Understanding Enums in Rust

I am having a hard time understanding the Enum custom type in Rust. In a broad way, The Book describes an Enum as a custom data type that has different variants. How should I think about these variants? Are these sub-types, or are these specific values that the Enum type can take?
Looking online I see examples like:
enum Day {
Monday,
Tuesday,
Wednesday,
Thursday,
Friday,
Saturday,
Sunday,
}
In the case above, the variants are the possible values of the Day type. But in The Book we see examples like:
struct Ipv4Addr {
// --snip--
}
struct Ipv6Addr {
// --snip--
}
enum IpAddr {
V4(Ipv4Addr),
V6(Ipv6Addr),
}
To me, it seems like IpAddr::V4 is a sub-type rather than a specific value, but a variable is really of type IpAddr and can have a value IpAddr::V4.
Does it make sense to make the distinction I mention above? What is the correct interpretation of an Enum?
Rust is a static, strongly typed language. It is also very fast. In many cases it is more efficient to use the stack, instead of the heap. However, when you use the stack Rust must know the size of the data that is needed. That's not a problem for simple fixed types like i16, u128, etc. It also isn't a problem for tuples, structs or arrays, because they have a fixed data structure with a known size.
However, sometimes you will need to use different data types, depending on some runtime condition/state. In languages like Java, .NET, JS, Python, PHP, etc., in such situations you will be using the heap (one way or another). In Rust you also have ways to use the heap, but that's often suboptimal. Enums in Rust allow you to define additional, variant-specific fields with custom data types. That can be very flexible and at the same time, in many cases, would be faster than solutions that make use of the heap.
Note that in languages like Java, you would often end up creating a hierarchy of classes to achieve what you can do in Rust with enums. Both approaches have their pros and cons. But if you come from a language like Java, you should keep that in mind.
Maybe a good example would be to think about how you would represent a JSON in your language of choice. If the JSON has a fixed data structure, you can use standard structs in Rust, classes in Java, etc. But what if you don't know the structure of a JSON object in advance? In most modern languages the parser would create some sort of a (Linked)HashMap that contains strings for the keys and some object instances (integers, strings, lists, maps, etc.) for the values. Compare that to serde's Value enum. Another example, which is not for JSON, but is conceptually similar in that you can read data of different types, is mysql's Value.
It might also be useful to understand how Rust allocates memory for enums. It basically determines (at compile time, of course) of all the variants, which one needs most memory. Let's say variant A needs 12 bytes, variant B needs 16 bytes, variant C needs 4 bytes. Rust will allocate 16 bytes for the associated data of every enum instance, because that's the minimum size that all variants can fit in.
It is reasonable to see the Day as a C-style enum. It describes all possible values of the type and has a numeric discriminant to identify each.
The IpAddr type is a tagged union. It is some tag (a number like in the c-style enum) followed by the value you give in brackets. It is not really a subtype, more a variant of IpAddr.
Once identified by its tag (which match and such do for you) you can use the values inside.

attribute having multiple types in class diagram

In UML class diagram, is it possible to represent an attribute that can have multiple types? For example, MyClass has an attribute named MyAttribute. How can I specify in class diagram that MyAttribute can assume float or string type value? An alternate option is to write MyAttribute: (https://learn.microsoft.com/en-us/visualstudio/modeling/uml-class-diagrams-guidelines?view=vs-2015), i.e. not specifying the type, but not specifying the type may create problems if people start to use their own types.
Thanks in advance.
One way to do this is to model a union of two different data types. You would define a data type that has two specializations, create a generalization set that is {complete, disjoint}, make the general data type abstract, and use the general data type as the attribute’s type.
You may have trouble convincing a code generator to map this correctly to a programming language, such as C++ or XSD, which can both represent this construct, but the UML would be perfectly clear to any reader.
A UML Attribut or Property can only have one type.
So if you want, for example, to allow both String and Float values you have to type your attribute with an Interface common to both of them like Object for example.
But of course, it will less precise because you allow other kind of values....
When you're dealing with untyped languages (like e.g. Python), none of your attributes have a specific type. In any typed language you decide at compile time which type an attribute can take. I don't know of any language that allows a set of types to be assigned to any attribute.
Assuming you're talking about untyped languages, you would add a constraint to your generally untyped attributes telling something like { must take either type A or B }. Of course, the compiler/interpreter will not help you in checking that constraints.

MSVC++ Class Cast to the a struct

I am currently reading an existing code in MS Visual C++ 6.0. I notice a code pattern where they cast object into a structure.
There is a CMemory object.
CMemory a;
MY_STRUCTURE_A* a = (MY_STRUCTURE_A*)(void *)a;
MY_STRUCTURE_B* a = (MY_STRUCTURE_B*)(void *)a;
I checked the Custom memory class and it really is a class object. It does have a = operator defined but I do not think that would allow it to be reinterpreted to a structure. Why is this being done. How is an object type being cast to different objects?
Any idea why this is being done? I know there is a reinterpret_cast and I am guessing that this technique of casting to void pointer to a structure pointer is similar. But I am not sure if it is the same. Is this pattern safe casting a class object to a struct?
Note: the CMemory is just an arbritary name of the object used. It is not part of the MFC class.
Added based on Necrolis' comment.
The CMemory and it has only 3 members declared in the following order (1) char pointer, (2) int specifying the allocated memory of (1), and (3) a previous and next pointer to other instance of CMemory. It also has a lot of member method. From what I understand, even if I directly cast a class to a structure. The class would start should start with the first member variable which is the char pointer.
class CMemory {
public:
CAMemory();
... Other methods
private:
char *m_pMemory;
int m_memorySize;
... Other field
}
Going by the name of the class and the casting, CMemory is more than likely a generic memory block tag (for a GC, arbitrary hash table etc), and to access the memory its tagging requires a cast. Of course this is a "best guess", it means nothing without seeing the full code for CMemory.
Is this safe, totally not, its not only UB, but there is no check (at least in your example) as to whether the object you casting to is the object represented by the memory layout. Also, with this being C++, they should be avoiding C casts (as you have noted. the double cast is in fact to get around compiler errors/warnings, which is always the worst way to solve them).

Haskell FFI for C recursive struct and union

I am trying to write Haskell FFI binding for some C structs. An example is below:
typedef struct s0{int a;
union{unsigned char b;
struct s0*c;
struct{unsigned char d[1];
}; };}*S;
My question is how to write the binding for it in chs (for c2hs) or hsc (for hsc2hs) format? I looked into the tutorials for c2hs but either didn't get enough information, or didn't understand it in the way, that would have helped me write the chs file for above definition.
I can generate haskell bindings using HSFFIG tool but it uses custom access method HSFFIG.FieldAccess.FieldAccess to define bindings. I prefer to write bindings that use core haskell FFI libraries, not third-party libraries.
Hence, this question about how to write a binding for recursive struct above in hsc format, or chs format that uses only core FFI libraries.
The actual definition is more complex, but once I figure out how to write above struct definition for c2hs or hsc2hs tools, I can go from there. I know Storable instances need to be defined for inner union and struct as well, but I don't know how to write wrappers for recursive definition like above. Especially, how do you access inside struct/union from outer struct? I looked into HSFFIG definitions, but the access methods are HSFFIG defined access methods. So, I was unable to figure out how to translate it to chs definition that uses only core FFI libraries.
The questions I have seen in StackOverflow seem to be about simpler definitions. If there is a similar answer somewhere else, I will appreciate pointers.
You can't magic up an equiv data structure in either c2hs or hsc2hs. However, you can do your own marshaling in c2hs with only a little work.
data MyType = Next MyType | MyChar Char | MyString String | MyEnd
Then use hsc2hs' newtype pointer functionality to declare a pointer for MyType (ie. s0). Then, write an explicit function using hsc2hs' accessors to recursively walk your structure and build up your Haskell structure. At each step you test if you've hit a null pointer and if so return a MyEnd (or, depending on the data encoding, just check if the int indicating the type in the union is negative one or whatever), otherwise proceed to parse out whatever you have, and if that thing is a pointer, proceed recursively.
You could do nearly the same thing with hsc2hs as well.

Does D have 'newtype'?

Does D have 'newtype' (as in Haskell).
It's a naive question, as I'm just skimming D, but Google didn't turn up anything useful.
In Haskell this is a way of making different types of the same thing distinct at compile time, but without incurring any runtime performance penalties.
e.g. you could make newtypes (doubles) for metres, seconds and kilograms. This would error at compile time if your program added a quantity in metres to a quantity in seconds, but would be just as fast at runtime as if both were doubles (which they are at runtime).
If D doesn't have something analogous to 'newtype', what are the accepted methods for dealing with dimensioned quantities?
Thanks,
Chris.
In D1.0 there is typedef, which is the strong typing from a predefined type to a 'newtype.'
D2.0 has removed this and only alias remains (what typedef is in C). There is talk about having a wrapper template that can strongly create a new type.
The issue with typedef was that there were good arguments for making the newtype a sub-type of the predefined type, and also good arguments for making it a super-type.
The semantics of typedef are that the base type is implicitly converted to the newtype, but the newtype is not converted to the base type or other types with the same base type. I am using base type here since:
typedef int Fish;
typedef Fish Cat;
Fish gold = 1;
Cat fluff = gold;
Will fail to compile.
And as of right now, 2.048 DMD still allows the use of typedef (but don't use it).
Having the base type convert to the newtype is useful so you don't have to write
meters = cast(meters) 12.7;
Funny, as he_the_great mentions, D1 had a strong typedef but noone used it, possibly because it was impossible to customize the exact semantics for each case. Possibly the simplest way to handle this situation, at least for primitive types, is to include a mixin template somewhere in Phobos that allows you to forward all operators but have the boilerplate to do this automatically generated via the mixin. Then you'd just create a wrapper struct and be all set.

Resources