Steam IO endianess for Read and Write attributes

I’m finally getting around to relearning Ada and I’m working with the networking example displayed here: Ada Programming/Libraries/GNAT.Sockets - Wikibooks, open books for an open world

I’m writing the equivalent programs in Plan 9 C with matching food.h, client.c, and server.c with the goal being that server.adb can be called by client.c and vice versa.

My issue is the endianess over the wire is that of the machine, little endian. I much prefer network order as that is what I am used to working with.

How can I switch the endianess of the ‘Read, ’Write or ‘Input and ‘Output attributes? Or is this a case where I need to write my own attribute routines?

Yes, you must implement these attributes yourself. In Ada you can override these for user-defined types.

P.S. For communication purpose stream attributes have limited use. Normally you would rather deal with network packets stored in a buffer, usually in a Stream_Element_Array. It is more efficient and more flexible because you need to validate the input. Then network and data representation protocols specify endianness and general encoding. Then some protocols use chunking, you don’t want to accumulate all serialized object in the memory before for a stream attribute or use a secondary task with a pipeline stream.

You have many options. One of them, to specify representation, see

1 Like

Thank you for the information. I have been reading through your Simple Components libraries; lots of good stuff in there as I work in industrial automation. I was studying your Modbus library as I have written a very light weight client and server library myself in c.

It has been a while since using the pure oop approach so it takes a while to understand the the entirety of the jungle. Would you say this is your preferred approach or are there other approaches using Ada?

I do not consider OO an “approach.” Yes, there is so-called OOA&D which is an approach. But I am rather agnostic to that. To me OO is just an advanced level of type system which allows you to express the notion of a set of types AKA “class.” If you need such a set and this abstraction level, you use “OO” if you do not then you do not.

As for automation and communication, it is very difficult not to use it. Even if you refrain from doing that you will inevitable produce a poor-man’s equivalent of.

Many would claim generics an alternative as generics too create classes. The main problem with generics that there is no objects of such classes (akin to class-wide objects). It is static polymorphism. That opens some possibilities but heavily limits the design. You might think you do not need such objects only to discover lately that you are stuck. So pragmatically, generics is the last choice usually deep at the implementation level where you would use generic containers instances etc.

The best way to use Ada is to used the type system to model the problem-space, then use that to solve your problem.

Perhaps the best way to design is to think about interfaces (in the general sense) and how you’re going to use things, how to fit them together.

The usage of OOP has been overblown in academia and “the industry” for the past 30 years. OOP really shines when you can group things into what are essentially hierarchical taxonomies, programming against the “base case”/interface at the ‘root(s)’ of those trees — a lot of stuff has been shoehorned into OOP that didn’t need to be, but there is one area where it shines as an excellently suited solution: linguistics and compilers (particularly internal representations).

2 Likes

Personally I have tried but still have not found OO (tagged types) to be beneficial for my embedded communication systems. So far, simpler solutions have won out but I have control of the whole codebase. The primary driver for tagged types in Ada was e.g. enabling building on top of an existing code base without re-certifying or re-compiling the base code. Something that I read Rust has I’d say feature requests but seems more like desires upon. Perhaps a little generics can go a long way but can quickly get out of hand where perhaps tagged types can step in or perhaps they are for different problems as @OneWingedShark says :thinking:. Sometimes code duplication seems to be the cleanest option too.

Despite some academic sources claiming that OOP is good for consolidating code-duplication, this is incorrect: OOP is for specialization. (Handling unifying otherwise duplicate code is the generic’s position.) — Ada’s generics are quite powerful and useful, allowing static polymorphism as well.

A compiler IR is perhaps the best way to illustrate the usefulness of OOP:

Type Base_Node is tagged null record;
 -- DO: Calls PROCESS, using Context as the stage for the next IR/Code-gen.
 Procedure Do     ( Object : in out Base_Node'Class; Context : in out Stager );
 -- PROCESS, builds the next stage from this node and its children.
 Procedure Process( Object : in out Base_Node; Context : in out Stager ) is abstract;
 -- RUN: Calls EXECUTE, using Context to interpret the node.
 Procedure Run    ( Object : in out Base_Node'Class; Context : in out Virtual_Machine );
 -- EXECUTE: Interprets the given node within the virtual-machine.
 Procedure Execute( Object : in out Base_Node; Context : in out Virtual_Machine ) is abstract;
 -- …

You can then have, say, a Conditional_Node-type which handles if and case statements/expressions, being the parent for all four of those [If_Statement/Case_Statement/If_Expression/If_Statement].

The interesting/useful property here being that every node in the AST here ‘knows’ (a) how to generate the next stage’s form, and (b) how to interpret itself on the given VM.

All good points.

I’m stuck thinking in C which I will chalk up as “growing pains.”

Indeed. I have been doing a bit of studying, writing small programs, realizing that types are how to lay out the problem space and build around that. It’s starting to click.

1 Like

This is incorrect. Considering Ada type system:

  • Subtypes are specialization
  • Tagged extension is generalization

I agree with respect to subtypes.
However extending tagged typs adds a special property which is exclusive for the derived type, so I see it as a specialization as well. The parent type has some properties, the derived one has an additional property the parent lacks.
In botany, there is the family Rosaceae with many genus like Fragaria, Rosa, Prunus, which then have special species. This can easily be mapped to tagged types, all above are abstract, only the species is real, that is, there exist plants of a certain species, but non of a certain genus.

It is the opposite direction. Specialization/generalization applies to the derived [sub]type.

Special species share properties of the family. This is why you can do that as long you stay with these only.

A better (infamous) example is the ellipse/circle problem. Circle is a specialization of Ellipse. Ellipse is a generalization of Circle. You can model that in either way: derive Circle from Ellipse (usually using a subtype) or derive Ellipse from Circle (usually by tagged extension). In either case you get problems because neither is a LSP sub/supertype of another.

I should have been more clear: OOP inheritance is for specialization of operations.
Your “generalmost” type in that family is the root-type, this is why (e.g.) for general IO there is no ‘seek’: you can’t ‘unsend’ radio (output) and you can’t ‘unreceive’ a sensor-signal (input).

That is not specialization. It is implementation the behaviour for some distinct type when you cannot inherit it by mere composition of type conversion with the old body. The reason for that can be specialization, generalization or both/none. Overriding is an implementation detail from the client point of view. You can consider all operations always overridden either implicitly per inheritance or explicitly by the programmer.

General: Parent → Special: Derived — Do you object and see this in the oppsite direction?

Derived shares properties with parent; of course you can modify them (override): The basic flower pattern is the same, but the sepals and petals are modified. Is this generalisation in your eyes?

Here we fully agree. To whom it may concern: Setzen, sechs!

I object because derivation is orthogonal to specialization/generalization. As I said you can derive Circle from Ellipse and you can derive Ellipse from Circle.

It is also orthogonal to inheritance. You can inherit and/or export upon derivation. For example Ada subtypes inherit and export. If you declare an operation on Positive it will be exported to Integer.

No. Overriding does not modify properties. It enforces them keeping behaviour intact. That is the core idea of the substitutability principle.

No, you are incorrect.
With respect to OOP, derivation and overriding are specializing the inherited type into the inheriting type. Recall that Ada defines a type as “A set of values, and a set of operations acting upon those values” — while a subtype is restricting the values from that set, overriding is replacing operations. (Granted, those operations can be reclaimed by type-/view-conversion up the hierarchy.)

Extension must needs be expansion of values (consider Circle as a shape, and Filled_Circle as derivation of Circle with an additional Color field for Fill_Color). Thus to convert Circle down the hierarchy we must provide a value for each field that doesn’t exist in the ancestor’s definition. (This is precisely what extension-aggregates are.)

This is incorrect, as Subtype is the application of some set of constraints (possibly null, ie “subtype renaming”) upon the set of values of a type. There is no new type involved, no ‘export’, no ‘inherited’.

There was some new-to-Ada person who had some questions, and was quite upset, when (the equivalent of) Positive'Image( X ) did not raise Constraint_Error when passed non-conforming (the equivalent of 0) values. — The explaination is simple, returning to Ada’s definition of a type as “A set of values and operations on those values”, the 'Image attribute being a query into the language for “the operation that produces a string from values of this type”, which is to say the function that is Integer'Image and thus could handle Natural and Positive as well. Said neophyte refused to acknowledge my explanations, doggedly determined to assert that the function should raise Constraint_Error. — The failure in his comprehension was the failure to think in terms of sets.

Indeed, recall and re-read what you wrote. Or simply recollect basic math: constrained set AKA subset is still a set… :grinning:

[ Ada has its own definition of type which is not helpful when discussing the universal concept of type, algebraic operations on them and properties of like specialization, derivation, inheritance, aggregation, delegation etc. You can express all Ada vocabulary in universal terms. When talking about Ada subtype it is definitely a universal type and definitely a distinct universal type. There are many reasons for that from the behaviour point of view to nominal type [in]equivalence and just for the sake of simplicity. Attempt to draw a line between types and not-so-types is distinction without a difference. There is nothing special in constraining. It is a type algebraic operation as any other. Any operation produces a result, a type, obviously. ]

Is there really a universal concept of type? I strongly doubt this claim.
If it existed, it could maximally be the intersection of any and all such ideas in the world (I avoid the term universe :wink: ), which then would be quite useless because it must be nearly empty.