I'm new to UML, how to describe the following class with a member function that takes void*?
// used on linux
#include <unistd.h>
class LinuxReadWrapper
{
public:
LinuxReadWrapper(){/** Ctor */}
~LinuxReadWrapper(){/** Dtor */}
ssize_t WrapperRead(void* buf)
{
return read(fd, buf, cnt);
}
private:
int fd{-1};
size_t cnt{0};
};
Thanks!
One solution is maybe to create a void or void* type in your model.
Then type your input parameter with it cf below.
This also dependsif you need this for documentation purpose only or also for code generation/reverse. In the last case, this will depends of the tool used...
Although Red Bear's answer is a very practical one, it is worth to remind that:
UML build-in primitive types are limited to: Integer, String, Boolean, UnlimitedNatural and Real
UML types can be extended with the help of a profile. Such a profile can extend the UML standard metamodel and introduce new «datatype». A profile is a package that you can import in all the models that need it. It is common to have a programming-language profile for the programming-language specific types.
A pointer (e.g. my_type *) requires extra-care, because in general the pointer is not the type relevant for the the UML model, since the pointer's purpose is to implements an association with an plain object (e.g. of class my_type).
In this regard a void* pointer is somewhat special, since it points to an object of unknown type, so keeping it as it is in the model is an understandable approach.
The good news is that datatypes are a standard feature of UML. So in any decent modelling tool you should find a way. For example:
Enterprise Architect lets you add new datatypes to your project
StarUML lets you add new datatypes to your project
Visual Pardigm lets you add new datatypes to the project configuration
Many tools just allow you to use whatever type you want. Visual Studio for example just lets you use any data type and will add unrecognized types to the model.
etc...
Related
I can see the following description in Ballerina docs regarding type equivalence and inheritance.
Ballerina is based on type equivalence, rather than type inheritance. The type system in Ballerina is based on set theory and, therefore, type equivalence has more meaning for this domain than type inheritance.
So can somebody please let me know how this set theory can be used to implement the concept of 'inheritance' or the a similar functionality? How we can do re-use of functions/class variables, etc? Is there a standard way of doing so? And please share if there are examples/blogs I can refer to.
https://v0-991.ballerina.io/learn/faq/#why-is-there-no-type-inheritance
If I'm not mistaken, you are trying to map the OOP concepts found in popular languages such as Java to Ballerina right? While it's tempting to do so, that can actually be a counter productive effort. Instead of attempting to think of a solution to a problem in an object oriented manner and trying to write OOP-style code in Ballerina, it would be better to take time to get familiar with the type system and other constructs Ballerina provides and build up the solution using those constructs. The Ballerina by Examples (BBEs) would be a good place to start.
Having said that, I'll try to briefly answer the questions you've raised. The Ballerina type system is structural. In Java, any user defined type is an object and you use inheritance to establish the relationships between the types. In Ballerina, we compare the "shape" of the value to check if it is compatible with a particular type. Every value has a shape, and a type is a set of such shapes. Here's what the 2020R1 spec of the language says regarding this and subtyping:
A type denotes a set of shapes. Subtyping in Ballerina is semantic: a type S is a subtype of type T if the set of shapes denoted by S is a subset of the set of shapes denoted by T. Every value has a corresponding shape. A shape is specific to a basic type: if two values have different basic types, then they have different shapes.
Let's take a concrete example using records to further explain this.
type Person record {
string name;
int age;
};
type Student record {
string name;
int age;
string school;
};
public function main() {
Student st = {name: "John Doe", age: 18, school: "XYZ Academy"};
Person p = st; // this is a valid assignment
io:println(p);
}
In the above code snippet we can safely use a Person reference to manipulate a Student value since a Student value is guaranteed to have the same fields as a Person value.
The Student record definition can be written as follows as well:
type Student record {
*Person; // this is a type reference
string school;
};
Referring a type as given above copies all the fields in the specified record to the current record. While this may look like inheritance, it's not. The definition above is equivalent to the the original definition we saw earlier.
In Ballerina, code is organized by modules. Similar to packages in Java, except that a module is made up of functions, type definitions (e.g., records, objects), services, listeners, constants etc. While objects are supported, it's just another type of values; not a unit of organization for code. Functions are a module level construct and if you intend to reuse it in other modules, it needs to have the public access modifier. To call the function, you need to import the module and qualify the function call with the module name. e.g.,
int x = foo:barFunction();
Sharing variables across modules is not allowed in Ballerina. However, you can have public constants in a module. e.g.,
public const PI = 3.14;
Hope this clears things up. If you are interested in the design of the language, you can refer to the language spec I mentioned earlier and to the following blog posts from James:
Ballerina Programming Language - Part 0: Context
Ballerina Programming Language - Part 1: Concept
Also, note that 0.991 is a heavily outdated version. I'd recommend taking a look at the current version (1.2.2).
Ballerina does not support the implementation inheritance or class-based inheritance that you see in OO languages like Java. What this means is that you cannot inherit code from types in Ballerina (e.g. Ballerina objects).
The term inheritance is an overloaded term. If you want to know more about sybtyping in Ballerina, then read Pubudu's answer. It explains how you can achieve interface inheritance in Ballerina. You can map his answer to Ballerina objects as well.
Coming from Delphi, I'm used to using class references (metaclasses) like this:
type
TClass = class of TForm;
var
x: TClass;
f: TForm;
begin
x := TForm;
f := x.Create();
f.ShowModal();
f.Free;
end;
Actually, every class X derived from TObject have a method called ClassType that returns a TClass that can be used to create instances of X.
Is there anything like that in C++?
Metaclasses do not exist in C++. Part of why is because metaclasses require virtual constructors and most-derived-to-base creation order, which are two things C++ does not have, but Delphi does.
However, in C++Builder specifically, there is limited support for Delphi metaclasses. The C++ compiler has a __classid() and __typeinfo() extension for retrieving a Delphi-compatible TMetaClass* pointer for any class derived from TObject. That pointer can be passed as-is to Delphi code (you can use Delphi .pas files in a C++Builder project).
The TApplication::CreateForm() method is implemented in Delphi and has a TMetaClass* parameter in C++ (despite its name, it can actually instantiate any class that derives from TComponent, if you do not mind the TApplication object being assigned as the Owner), for example:
TForm *f;
Application->CreateForm(__classid(TForm), &f);
f->ShowModal();
delete f;
Or you can write your own custom Delphi code if you need more control over the constructor call:
unit CreateAFormUnit;
interface
uses
Classes, Forms;
function CreateAForm(AClass: TFormClass; AOwner: TComponent): TForm;
implementation
function CreateAForm(AClass: TFormClass; AOwner: TComponent): TForm;
begin
Result := AClass.Create(AOwner);
end;
end.
#include "CreateAFormUnit.hpp"
TForm *f = CreateAForm(__classid(TForm), SomeOwner);
f->ShowModal();
delete f;
Apparently modern Delphi supports metaclasses in much the same way as original Smalltalk.
There is nothing like that in C++.
One main problem with emulating that feature in C++, having run-time dynamic assignment of values that represent type, and being able to create instances from such values, is that in C++ it's necessary to statically know the constructors of a type in order to instantiate.
Probably you can achieve much of the same high-level goal by using C++ static polymorphism, which includes function overloading and the template mechanism, instead of extreme runtime polymorphism with metaclasses.
However, one way to emulate the effect with C++, is to use cloneable exemplar-objects, and/or almost the same idea, polymorphic object factory objects. The former is quite unusual, the latter can be encountered now and then (mostly the difference is where the parameterization occurs: with the examplar-object it's that object's state, while with the object factory it's arguments to the creation function). Personally I would stay away from that, because C++ is designed for static typing, and this idea is about cajoling C++ into emulating a language with very different characteristics and programming style etc.
Type information does not exist at runtime with C++. (Except when enabling RTTI but it is still different than what you need)
A common idiom is to create a virtual clone() method that obviously clones the object which is usually in some prototypical state. It is similar to a constructor, but the concrete type is resolved at runtime.
class Object
{
public:
virtual Object* clone() const = 0;
};
If you don't mind spending some time examining foreign sources, you can take a look at how a project does it: https://github.com/rheit/zdoom/blob/master/src/dobjtype.h (note: this is a quite big and evolving source port of Doom, so be advised even just reading will take quite some time). Look at PClass and related types. I don't know what is done here exactly, but from my limited knowledge they construct a structure with necessary metatable for each class and use some preprocessor magic in form of defines for readability (or something else). Their approach allows seamlessly create usual C++ classes, but adds support for PClass::FindClass("SomeClass") to get the class reference and use that as needed, for example to create an instance of the class. It also can check inheritance, create new classes on the fly and replace classes by others, i. e. you can replace CDoesntWorksUnderWinXP by CWorksEverywhere (as an example, they use it differently of course). I had a quick research back then, their approach isn't exceptional, it was explained on some sites but since I had only so much interest I don't remember details.
What would be the best representation of a C/C++ function pointer (fp) in an UML structural diagram?
I'm thinking about using an interface element, may be even if 'degenerate' with the constraint of having at most a single operation declared.
I found some proposal in this document: C and UML Synchronization User Guide, Section 5.7.4. But this sounds quite cumbersome and not very useful in practice. Even if right from a very low level of semantic view. Here's a diagram showing their concept briefly:
IMHO in C and C++ function pointers are used as such a narrowed view of an interface which only provides a single function and it's signature. In C fp's would be used also to implement more complex interfaces declaring a struct containing a set of function pointers.
I think I can even manage to get my particular UML tool (Enterprise Architect) to forward generate the correct code, and synchronizing with code changes without harm.
My questions are:
Would declaration of fp's as part of interface elements in UML proivde a correct semantic view?
What kind of stereotype should be used for single fp declaration? At least I need to provide a typedef in code so this would be my guts choice.(I found this stereotype is proprietary for Enterprise Architect) and I need to define an appropriate stereotype to get the code generation adapted. Actually I have chosen the stereotype name 'delegate', does this have any implications or semantic collisions?
As for C++, would be nesting a 'delegate' sterotyped interface with in a class element enough to express a class member function pointer correctly?
Here's a sample diagram of my thoughts for C language representation:
This is the C code that should be generated from the above model:
struct Interface1;
typedef int (*CallbackFunc)(struct Interface1*);
typedef struct Interface1
{
typedef void (*func1Ptr)(struct Interface1*, int, char*);
typedef int (*func2Ptr)(struct Interface1*, char*);
typedef int (*func3Ptr)(struct Interface1*, CallbackFunc);
func1Ptr func1;
func2Ptr func2;
func3Ptr func3;
void* instance;
};
/* The following extern declarations are only dummies to satisfy code
* reverse engineering, and never should be called.
*/
extern void func1(struct Interface1* self, int p1, char* p2) = 0;
extern int func2(struct Interface1* self, char*) = 0;
extern int func3(struct Interface1* self, CallbackFunc p1) = 0;
EDIT:
The whole problem boils down what would be the best way with the UML tool at hand and its specific code engineering capabilities. Thus I have added the enterprise-architect tag.
EA's help file has the following to say on the subject of function pointers:
When importing C++ source code, Enterprise Architect ignores function pointer declarations. To import them into your model you could create a typedef to define a function pointer type, then declare function pointers using that type. Function pointers declared in this way are imported as attributes of the function pointer type.
Note "could." This is from the C++ section, the C section doesn't mention function pointers at all. So they're not well supported, which in turn is of course due to the gap between the modelling and programming communities: non-trivial language concepts are simply not supported in UML, so any solution will by necessity be tool-specific.
My suggestion is a bit involved and it's a little bit hacky, but I think it should work pretty well.
Because in UML operations are not first-class and cannot be used as data types, my response is to create first-class entities for them - in other words, define function pointer types as classes.
These classes will serve two purposes: the class name will reflect the function's type signature so as to make it look familiar to the programmer in the diagrams, while a set of tagged values will represent the actual parameter and return types for use in code generation.
0) You may want to set up an MDG Technology for steps 1-4.
1) Define a tagged value type "retval" with the Detail "Type=RefGUID;Values=Class;"
2) Define a further set of tagged value types with the same Detail named "par1", "par2" and so on.
3) Define a profile with a Class stereotype "funptr" containing a "retval" tagged value (but no "par" tags).
4) Modify the code generation scripts Attribute Declaration and Parameter to retrieve the "retval" (always) and "par1" - "parN" (where defined) and generate correct syntax for them. This will be the tricky bit and I haven't actually done this. I think it can be done without too much effort, but you'll have to try it. You should also make sure that no code is generated for "funptr" class definitions as they represent anonymous types, not typedefs.
5) In your target project, define a set of classes to represent the primitive C types.
With this, you can define a function pointer type as a «funptr» class with a name like "long(*)(char)" for a function that takes a char and returns a long.
In the "retval" tag, select the "long" class you defined in step 4.
Add the "par1" tag manually, and select the "char" class as above.
You can now use this class as the type of an attribute or parameter, or anywhere else where EA allows a class reference (such as in the "par1" tag of a different «funptr» class; this allows you to easily create pointer types for functions where one of the parameters is itself of a function pointer type).
The hackiest bit here is the numbered "par1" - "parN" tags. While it is possible in EA to define several tags with the same name (you may have to change the tagged value window options to see them), I don't think you could retrieve the different values in the code generation script (and even if you could I don't think the order would necessarily be preserved, and parameter order is important in C). So you'd need to decide the maximum number of parameters beforehand. Not a huge problem in practice; setting up say 20 parameters should be plenty.
This method is of no help for reverse engineering, as EA 9 does not allow you to customize the reverse-engineering process. However, the upcoming EA 10 (currently in RC 1) will allow this, although I haven't looked at it myself so I don't know what form this will take.
Defining of function pointers is out of scope of UML specification. What is more, it is language-specific feature that is not supported by many UML modeling software. So I think that the general answer to your first question suggests avoiding of this feature. Tricks you provided are relevant to Enterprise Architect only and are not compatible with other UML modeling tools. Here is how function pointers is supported in some other UML software:
MagicDraw UML uses <<C++FunctionPtr>> stereotypes for FP class members and <<C++FunctionSignature>> for function prototype.
Sample of code (taken from official site -- see "Modeling typedef and function pointer for C++ code generation" viewlet):
class Pointer
{
void (f*) ( int i );
}
Corresponding UML model:
Objecteering defines FP attributes with corresponding C++ TypeExpr note.
Rational Software Architect from IBM doesn't support function pointers. User might add them to generated code in user-defined sections that are leaved untouched during code->UML and UML->code transformations.
Seems correct to me. I'm not sure you should dive into the low-level details of descripting the type and relation of your single function pointer. I usually find that description an interface is enough detalization without the need to decompose the internal elements of it.
I think you could virtually wrap the function pointer with a class. I think UML has not to be blueprint level to the code, documenting the concept is more important.
My feeling is that you desire to map UML interfaces to the struct-with-function-pointers C idiom.
Interface1 is the important element in your model. Declaring function pointer object types all over the place will make your diagrams illegible.
Enterprise Architect allows you to specify your own code generators. Look for the Code Template Framework. You should be able to modify the preexisting code generator for C with the aid of a new stereotype or two.
I have been able to get something sort of working with Enterprise Architect. Its a bit of a hacky solution, but it meets my needs. What I did:
Create a new class stereotype named FuncPtr. I followed the guide here: http://www.sparxsystems.com/enterprise_architect_user_guide/10/extending_uml_models/addingelementsandmetaclass.html
When I did this I made a new view for the profile. So I can keep it contained outside of my main project.
Modified the Class code templates. Basically selecting the C language and start with the Class Template and hit the 'Add New Stereotype Override' and add in FuncPtr as a new override.
Add in the following code to that new template:
%PI="\n"%
%ClassNotes%
typedef %classTag:"returnType"% (*%className%)(
%list="Attribute" #separator=",\n" #indent=" "%
);
Modified the Attribute Declaration code template. Same way as before, adding in a new Stereotype
Add in the following code to the new template:
%PI=""% %attConst=="T" ? "const" : ""%
%attType%
%attContainment=="By Reference" ? "*" : ""%
%attName%
That's all that I had to do to get function pointers in place in Enterprise Architect. When I want to define a function pointer I just:
Create a regular class
Add in the tag 'returnType' with the type of return I want
Add in attributes for the parameters.
This way it'll create a new type that can be included as attributes or parameters in other classes (structures), and operators. I didn't make it an operator itself because then it wouldn't have been referenced inside the tool as a type you can select.
So its a bit hacky, using special stereotyped classes as typedefs to function pointers.
Like your first example I would use a Classifier but hide it away in a profile. I think they've included it for clarity of the explaining the concept; but in practice the whole idea of stereotypes is abstract away details into profiles to avoid the 'noise' problem. EA is pretty good for handling Profiles.
Where I differ from your first example is that I would Classify the Primitive Type Stereotype not the Data Type stereotype. Data Type is a Domain scope object, while Primitive Type is an atomic element with semantics defined out side the scope of UML. That is not to say you cannot add notes, especially in the profile or give it a very clear stereotype name like functionPointer.
I have a template class representing a UI widget. The class is called (surprisingly) Widget. The class defines graphics_type (via typedef or similar) which could be a cairo_t, a HDC, a CDC* or something similar. In other words, Widget defines a type called graphics_type which it uses for drawing stuff.
How do I represent the relationship between Widget and graphics_type using UML?
Bonus question: Do any C++ programmers here find UML useful in these situations?
Sparx EA is linking typedefs to the aliased type via generalization. At least that is what happens when you import from source. The C++ generation template overrides Class if the stereotype is <<typedef>>. If the typedef is using a template, EA inserts:
typedef templateName<alias> alias;
Otherwise, it inserts:
typedef aliasedClass alias;
I went searching because I want:
typedef aliasedClass* class_ptr;
and I don't know how to express the pointer part in UML. I was hoping to find some standard way of expressing the construct but no luck.
Option 1: create a template that is just a pointer-maker:
template class _ptr { /* TMTFWIW */ }
Option 2: use a tag in my PIM-to-C++ PSM transform to insert the *.
I think I'll go with #2.
publib.boulder.ibm.com has a great deal of documentation on many subjects, including quite a bit on UML. Their rule for many C++-specific constructs, including typedef and others, is pretty much just as #David Rodriguez stated.
Each has its own answer to the question of usefulness of UML. Maybe UML is good for very big projects, but I have nothing to say here.
In my practice I find it uneffective to develop code based on UML diagrams because class declaration in C++ is very informative and clear itself, especially if you define methods outside class body. Making aditional diagrams takes the same time but shows nothing new.
The second thing about class relation diagrams is that they are very good if built automatically from the existing code. Doxygen can do this for example. The plus is that you don't spend extra time for UML and can easily inspect current implementation. Also, making changes by hand on a printed paper with such а diagram is very handy for refactoring.
I already figured out to use polymorphism and have the list store the pointer to the baseClass, but after successfully placing it there, I would like to know what class the object was originally. I am using templates for the classes, and wanted to have an another field which would be an enum of basic types.
Now the question: is there a way to check (during runtime or during compilation) an
(if T == int)
field = INT
I though maybe something with the preprocessor but I'm not familiar with that.
The whole idea behind polymorphism is to hide the specific implementation making it transparent in your program flow. Using type of class as an indicator will make your code bloat with if statements and will be harder to maintain.
I suggest you reconsider your design and make an abstract class with the intended behavior methods and use this class type as the list objects type. Than for each object call the interface method (which was declared in the abstract class and implemented in the deriving classes)
You can use operator typeid.
For example, if T is a pointer to a base class:
if (typeid(SomeDerivedClass) == typeid(*T))
...
(It is somewhat unclear for me why you speak about int in connection with polymorphism. int cannot be derived from.)
What you are probably looking for is known as type traits. They allow you to determine and act on the attributes of a specific type. You could start with std::is_integral() and std::is_floating_point() and build from there depending on your requirements.
enum Type
{
Unknown,
Integral,
Float
};
....
Type field = Unknown;
if(std::is_integral<T>::value)
{
field = Integral;
}
else if(std::is_floating_point<T>::value)
{
field = Float;
}
The C++ preprocessor knows nothing about C++. It is a generic symbol manipulator which can be used with most any programming language, or for that matter, any text processing application, such as a feature of word or equation layout processing.
You might look into the typeid operator as one way to build such a mechanism, though heed the Misuses of RTTI section further down on that page.