Global operations on all class instances - oop

There is the question: there are many fields instantiated in my CFD code and I want to count them all and write their contents to an external file (for example to save my calculation progress). My field derived type has only one component:
type scalar_field
real , dimension (:,:,:) , allocatable :: nodes
contains
! some procedures
end type
I am trying to create another type with counters and pointers to the node components of all fields. Something like this:
type field_counter
private
real ,pointer :: scalar_fields(:,:,:,:)
integer :: number_of_scalars
contains
procedure set_num_scalar_fields
procedure set_scalar_field_pointer
procedure output_scalars
end type
The main idea is to pass object of this type to the field constructor , where num_scalar_field attribute is incremented and slice of pointer array scalar_fields(i,:,:,:) is associated with nodes array. After that I would be able to print all contents of scalar fields via calling scalar_fields pointer array.
But I don't know whether it would work and whether it is an easiest way to perform this task, and I'll have to add the target attribute to each nodes array, which seems a bit overwhelming. Maybe there is some OOP design pattern for this task, or maybe anybody already have solved this kind of problem?

If, as you say, the number of fields is static after the program has initialised, I'd be inclined to create an array of them, like this:
type(scalar_field), dimension(:), allocatable :: all_fields
Once your program starts and figures out how many fields to allocate, then it can go ahead and allocate them
allocate(all_fields(num))
and you can reference individual fields as you would any other array element, like this:
all_fields(1)
I don't see the need for a new user-defined type for the array of scalar fields nor any pointers or any of that stuff. Mind you, I'm not sure I see the need for any OO at all here, back in the day I'd have just defined all_fields as a rank-4 array and used the last index as the identifier of the field.

Related

Structure where the data type of a member differs

Maybe superfluous, but some intro...
I am rewriting an add-in for my CAD-application (using VB.NET).
This add-in reads, via an API, a bunch of metadata from a file, presents it in a Form. This data can then be (partially) changed and written back to the file.
This metadata is accessible in a consistent way, however the data type is not the same everywhere (String, Currency, Date, Boolean, Long and IPictureDisp).
Currently I have a much too complex class with several arrays. I thought it might be smarter to create a structure. The problem is the varying data type.
Is it possible to define a structure with a member with varying datat type, or am I forced to define a different structure for each data type?
You have a few options...
1: Use Object
Nice and simple, every data type inherits from Object - so if your struct contains a property of type Object, you can put pretty much any data type in there
From the docs:
The Object data type can point to data of any data type, including any object instance your application recognizes. Use Object when you do not know at compile time what data type the variable might point to.
However, this does mean that you will get next to no help from the compiler when you are trying to write code using this property. You will also probably have to cast any time you need to do anything type-specific
2: Generic Types
This will not fit situations where you are not sure of the type. You can create a generic struct using the Of syntax.
You'd create it as so:
Structure MyStructure(Of T)
'our changing type
Dim MyCustomData As T
'...alongside regular types
Dim Name As String
Dim OtherThing As Integer
End Structure
and then when you need to create the structure, you'd simply pass the type in and assign the value
Dim struct As New MyStructure(Of Integer)
struct.MyCustomData = 123
Dim struct2 As New MyStructure(Of String)
struct2.MyCustomData = "a"

Illegal characters in OrientDB graph for property-type string

I use the graph version of OrientDB. Now I created a schema-less class, where I want to index a variable. This variable needs to become a property first. But when I try to create this property - of type string (or binary, or whatever) - it responds:
com.orientechnologies.orient.core.exception.OSchemaException: The database contains some schema-less data in the property 'clazz.clazz_name' that is not compatible with the type STRING. Fix those records and change the schema again [ONetworkProtocolHttpDb]
So I need to fix something, but what? What characters are illegal for a variable to become a property so that it can be indexed? (BTW, lists are also not an option)
There was indeed a problem I created.
I created a super-class where the property had to be created. One of the sub-classes inserted a List instead of a String. So when querying all vertices of sub-type
final Iterable<Vertex> iterable = this.graph.getVerticesOfClass("clazz");
I printed all types of clazz_name by vertex.getProperty("clazz_name").getClass().getName() where I saw OLinkedList. Reinserting those vertices fixed my problem.

Frege: can I derive "Show" for a recursive type?

I'm trying to implement the classical tree structure in frege, which works nicely as long as I don't use "derive":
data Tree a = Node a (Tree a) (Tree a)
| Empty
derive Show Tree
gives me
realworld/chapter3/E_Recursive_Types.fr:7: kind error,
type constructor `Tree` has kind *->*, expected was *
Is this not supported or do I have to declare it differently?
Welcome to the world of type kinds!
You must give the full type of the items you want to show. Tree is not a type (kind *), but something that needs a type parameter to become one (kind * -> *).
Try
derive Show (Tree a)
Note that this is shorthand for
derive Show (Show a => Tree a)
which resembles the fact that, to show a tree, you need to also know how to show the values in the tree (at least, the code generated by derive will need to know this - of course, one could write an instance manually that prints just the shape of the tree and so would not need it).
Generally, the kind needed in instances for every type class is fixed. The error message tells you that you need kind * for Show.
EDIT: eliminate another possible misconception
Note that this has nothing to do with your type being recursive. Let's take, for example, the definition of optional values:
data Maybe a = Nothing | Just a
This type is not recursive, and yet we still cannot say:
derive Show Maybe -- same kind error as above!!
But, given the following type class:
class ListSource c -- things we can make a list from
toList :: c a -> [a]
we need say:
instance ListSource Maybe where
toList (Just x) = [x]
toList Nothing = []
(instanceand derive are equivalent for the sake of this discussion, both make instances, the difference being that derive generates the instance functions automatically for certain type classes.)
It is, admittedly, not obvious why it is this way in one case and differntly in the other. The key is, in every case the type of the class operation we want to use. For example, in class Show we have:
class Show s where
show :: s -> String
Now, we see that the so called class type variable s (which represents any future instantiated type expression) appears on its own on the left of the function array. This, of course, indicates that s must be a plain type (kind *), because we pass a value to show and every value has per definition a type of kind *. We can have values of types Int or Maybe Int or Tree String, but no value ever has a type Maybe or Tree.
On the other hand, in the definition of ListSource, the class type variable c is applied to some other type variable a in the type of toList, which also appears as list element type. From the latter, we can conclude, that a has kind * (because list elements are values). We know, that the type to the left and to the right of a function arrow must have kind * also, since functions take and return values. Therefore, c a has kind *. Thus, c alone is something that, when applied to a type of kind * yields a type of kind *. This is written * -> *.
This means, in plain english, when we want to make an instance for ListSource we need the type constructor of some "container" type that is parameterized with another type. Tree and Maybe would be possible here, but not Int.

Newbie question: how do I create a class to hold data in Visual Basic Studio?

I'm really sorry. This must seem like an incredibly stupid question, but unless I ask I'll never figure it out. I'm trying to write a program to read in a csv file in Visual Basic (tried and gave up on C#) and I asked a friend of mine who is much better at programming than I am. He said I should create a class to hold the data that I read in.
The problem is, I've never created a class before, not in VB, Java, or anything. I know all the terms associated with classes, I understand at a high level how classes work no problem. But I suck at the actual details of making one.
So here's what I did:
Public Class TsvData
Property fullDataSet() As Array
Get
Return ?????
End Get
Set(ByVal value As Array)
End Set
End Property
End Class
I got as far as the question marks and I'm stuck.
The class is going to hold a lot of data, so I made it an array. That could be a bad move. I don't know. All i know is that it can't be a String and it certainly can't be an Integer or a Float.
As for the Getter and Setter, the reason I put the question marks in is because I want to return the whole array there. The class will eventually have other properties which are basically permutations of the same data, but this is the full set that I will use when I want to save it out or something. Now I want to return the whole Array, but typing "Return fullDataSet()" doesn't seem like a good idea. I mean, the name of the property is "fullDataSet()." It will just make some kind of loop. But there is no other data to return.
Should I Dim yet another array inside the property, which already is an array, and return that instead?
Instead of writing your own class, you could get yourself familiar with the pre-defined class System.Data.DataTable and then use that for holding CSV data.
In the last few years that I've been programming, I've never actually used a multi-dimensional array, and I'd advise you not to use them, either. There's usually ways of achieving the same with a better data structure. For example, consider creating a class (let's call it CsvRecord) that holds only one record; that is, only one line from the CSV file. Then use any of the standard collection types from the System.Collections.Generic namespace (e.g. List(Of CsvRecord)) to hold the entire data (ie. all lines) in the CSV file. This effectively reduces the problem to, "How do I read in one line of CSV data?"
If you want to take suggestion #2 even further, do as cHao says and don't simply lay out the information you've read as a CsvRecord; instead, create an object that reflects the actual content. For example, if your CSV file contains product–price information, call your CSV record class ProductInfo or something more fitting.
If, however, you want to go on with your current approach, you will need a backing field for the property, as demonstrated by Philipp's answer. Your property then becomes a "façade" that only delegates to this backing field. This is not absolutely necessary: You could simply make the backing field Public and let the user of your class access it directly, though that is not considered a good practice.
Ideally, you ought to have a class representing the specific data you want to read in. Setting an entire array at once is asking for trouble; some programs that read {C,T}SV files will freak out if all rows don't have the same number of columns, which is exceedingly easy to do if you can set the data to be an array of arbitrary length.
If you're trying to represent arbitrary data, frankly, you'd do just as well to use a List(Of String). If it's meant to be a table, you could instead read in the first line and make it a list as above (let's call it "headers"), and then make each row a Dictionary(Of String, String). (Let's call each row "row", and the collection (a list of these dictionary objects) "rows".) Just read in the line, split it like you did the first, and say something like row(headers(column number)) = value for each column, and then stuff it into 'rows'.
Or, you could use the data classes (System.Data.DataTable and System.Data.DataSet would do wonders here).
Usually you use a private member to store the actual data:
Public Class TsvData
Private _fullDataSet As String()
Public Property FullDataSet() As String()
Get
Return _fullDataSet
End Get
Set(ByVal value As String())
_fullDataSet = value
End Set
End Property
Note that this is an instance of bad design since it couples a concept to a concrete representation and allows the clients of the class to modify the internals without any error checking. Returning a ReadOnlyCollection or some dedicated container would be better.

ABAP create object

Below is a code snippet that is creating object.
Form userexit_save_document_prepare.
data: /bks/exitmanager type ref to /bks/exit_manager.
create object /bks/exitmanager
exporting main_prog = 'SAPMV45A'
exit_form = 'USEREXIT_SAVE_DOCUMENT_PREPARE'.
include /bks/exitman.
ENDFORM.
I got this from the documentation
For performance reasons, the parameters "main_prog" and "exit_form" should be filled, in the case of userexits, which are performed very often like "user_field_modification" in "SAPMV45A" which is called for every single screen-field.
1) What happened exactly behind when create object /bks/exitmanager is called? memory allocated for the object etc?
2) Why for performance reasons the exporting parameters of create object needs to be filled?
I'm not 100% sure, but here is my best guess:
an object called /bks/exitmanager is constructed (which is an oject of the class /bks/exit_manager or more specific a reference/"pointer" to an object of this class) .. the required memory allocated etc., but also the "constructor" code is called (probably sets some instance variables as passed to the call).
If you're explicitly passing these parameters, they don't have to be "calculated" at run-time (e.g. by looking at the call stack). This should save some time, especially if it would have to be done quite often (as described in the documentation).
It would help to see what /bks/exit_manager actually is, and a brief explanation of what you are trying to accomplish.
Expanding on what IronGoofy wrote:
data: /bks/exitmanager type ref to /bks/exit_manager
This creates a reference pointer in the ABAP memory of your program, much like a field symbol. Also it must be already delared. If it is in the include, you need to move the include.
create object /bks/exitmanager
exporting main_prog = 'SAPMV45A'
exit_form = 'USEREXIT_SAVE_DOCUMENT_PREPARE'.
This creates an object instance based on the declared class, and assigns it to the referance pointer. It does this by calling the constructor method first.
Only by examing /bks/exit_manager will you find out exactly what you need to export.
It's impossible to tell what's going on and why the parameters should be passed without taking a look at the constructor of /BKS/EXIT_MANAGER. It's a common pattern though to keep a buffer of settings (think of a static hashed table with the key being the parameters and the value holding whatever is complicated and time-consuming to fetch). In this case, I would have expected a protected constructor that cannot be accessed directly, but only using a static factory method that uses a hashed table to keep the references of the exit handler itself - optimally using weak references...