Fortran derived type inheritance - oop

Let's say I have a derived type bar_a that is included in derived type foo_a as variable bar.
Now I want to extend bar_a and create a new derived type named bar_b. I tried the following:
program main
implicit none
! Base types -----------
type :: bar_a
integer :: a
end type bar_a
type :: foo_a
type(bar_a) :: bar
end type foo_a
! Extended types -------
type, extends(bar_a) :: bar_b
integer :: b
end type bar_b
type, extends(foo_a) :: foo_b
type(bar_b) :: bar ! <-- Component ‘bar’ at (1) already in the parent type
end type foo_b
! ----------------------
type(foo_b) :: foo
print *, foo%bar%a
print *, foo%bar%b
end program main
but I get a compiler error: "the component ‘bar’ at (1) already in the parent type".
Is there a way to extend foo_a so that it includes the new derived type bar_b as I tried, or is there any way to "override" the bar variable declaration? I would like to inherit the type bound procedures that would be a part of foo_a in foo_b.

When I try to compile I get a better message:
aa.f90:21:22:
10 | type :: foo_a
| 2
......
21 | type(bar_b) :: bar ! <-- Component ‘bar’ already in the parent type
| 1
Error: Component ‘bar’ at (1) already in the parent type at (2)
and this seems logical you try to extend foo_a with an element with the name bar, but the type that you extend (from the definition at line 10) already has a variable bar at line 11 and you try to add another bar at line 21.

Related

Sorting List of Objects Containing Maybe Time.Posix

I have a List of custom types that I would like to sort on one attribute which is of type Maybe Time.Posix. In reading the docs I've come to the conclusion I should use List.sortWith, as neither Maybe nor Time.Posix values are comparable. I've written a set of functions to prepare the values so they are comparable. The challenge that I'm facing, though, is pulling the values from the types in the list.
Here are the functions:
maybeCompare : (a -> a -> Order) -> Maybe a -> Maybe a -> Order
maybeCompare f a b =
case a of
Just some_a ->
case b of
Just some_b ->
f some_a some_b
Nothing ->
GT
Nothing ->
LT
posixCompare : Time.Posix -> Time.Posix -> Order
posixCompare a b = compare (posixToMillis(a)) (posixToMillis(b))
posMay = maybeCompare (posixCompare)
Which I combine and use like this:
List.sortWith (posMay .time) objList
On data that looks like this:
obj1 = {id=1,time= Just time1}
obj2 = {id=2,time= Just time2}
obj3 = {id=3,time= Just time3}
obj4 = {id=4,time= Just time4}
obj5 = {id=5,time= Nothing}
objList = obj1 :: obj2 :: obj3 :: obj4 :: obj5 :: []
Now, this approach works for a list like this List (Maybe Time.Posix). By which I mean I get the output I expect, the list is sorted on the Posix time with the Nothing values in the desired location.
However, for a List of types where Maybe Time.Posix is one of the values I get this error (one of many, but I think this is the source):
List.sortWith (posMay .time) objList
^^^^^
This .time field access function has type:
{ b | time : a } -> a
But `posMay` needs the 1st argument to be:
Maybe Time.Posix
Is there are way to make the types of my functions align to sort this kind of data? Or, should I rethink my approach?
I've created a working example at https://ellie-app.com/8dp2qD6fDzBa1
Your posMay function is of the type Maybe a -> Maybe a -> Order, so it's not expecting .time, which is a function of type {id:Int,time:Maybe Posix} -> Maybe Posix.
Instead, you can create a different function which shims between posMay and List.sortWith, which would look like this: List.sortWith (\a b -> posMay a.time b.time)
If you want to be able to pass a getter function to posMay, you could rewrite it to accept that function:
posMay getter a b =
maybeCompare posixCompare (getter a) (getter b)
Then, you would use it like this: List.sortWith (posMay .time) (or List.sortWith (posMay identity) for a List (Maybe Posix). A version that works like this is at https://ellie-app.com/8dp7gm3qthka1

ABAP method call within a for-loop

Pretty new to ABAP. I've got a class "Truck" ("vrachtwagen") which has a table attribute it_pakket (packages in the truck). I've written a method to write the contents of this table to the screen (DisplayLading). I want to do this for each truck, so I call this method in a for-loop. The program runs without errors, but the output doesn't show up on the screen.
REPORT ZPR412_OO_OEF1.
CLASS CPakket DEFINITION.
PUBLIC SECTION.
DATA: Id TYPE I READ-ONLY,
aantal TYPE I,
bestemmeling TYPE STRING.
METHODS: SetID IMPORTING ID TYPE I.
ENDCLASS.
CLASS CPakket IMPLEMENTATION.
METHOD SetID.
me->Id = ID.
ENDMETHOD.
ENDCLASS.
CLASS CVrachtwagen DEFINITION.
PUBLIC SECTION.
DATA: Id TYPE I READ-ONLY.
METHODS: SetID IMPORTING ID TYPE I,
LaadPakket IMPORTING Pakket TYPE REF TO CPakket,
LosPakket IMPORTING Pakket TYPE REF TO CPakket,
DisplayLading.
PRIVATE SECTION.
DATA: it_pakket TYPE STANDARD TABLE OF REF TO CPakket,
pakket TYPE REF TO CPakket.
ENDCLASS.
CLASS CVrachtwagen IMPLEMENTATION.
METHOD SetID.
me->Id = ID.
ENDMETHOD.
METHOD LaadPakket.
APPEND Pakket TO it_pakket.
ENDMETHOD.
METHOD LosPakket.
ENDMETHOD.
METHOD DisplayLading.
LOOP AT me->it_pakket into pakket.
WRITE:/ pakket->Id, pakket->aantal, pakket->bestemmeling.
ENDLOOP.
ENDMETHOD.
ENDCLASS.
DATA:
vrachtwagen TYPE REF TO CVrachtwagen,
it_vrachtwagens TYPE STANDARD TABLE OF REF TO CVrachtwagen,
pakket TYPE REF TO CPakket,
it_pakket TYPE STANDARD TABLE OF REF TO CPakket,
s TYPE string.
start-of-selection.
DO 2 TIMES.
CREATE OBJECT vrachtwagen.
CALL METHOD vrachtwagen->SetId EXPORTING Id = sy-index.
APPEND vrachtwagen TO it_vrachtwagens.
ENDDO.
CREATE OBJECT pakket.
CALL METHOD pakket->SetId EXPORTING Id = 1.
pakket->aantal = 5.
pakket->bestemmeling = 'Bob'.
APPEND pakket TO it_pakket.
CREATE OBJECT pakket.
CALL METHOD pakket->SetId EXPORTING Id = 2.
pakket->aantal = 2.
pakket->bestemmeling = 'Jan'.
APPEND pakket TO it_pakket.
CREATE OBJECT pakket.
CALL METHOD pakket->SetId EXPORTING Id = 3.
pakket->aantal = 1.
pakket->bestemmeling = 'Piet'.
APPEND pakket TO it_pakket.
LOOP AT it_vrachtwagens INTO vrachtwagen.
CASE sy-index.
WHEN 1.
loop at it_pakket into pakket.
if sy-index lt 3.
vrachtwagen->LaadPakket( pakket ).
endif.
endloop.
WHEN 2.
read table it_pakket into pakket index 3.
vrachtwagen->LaadPakket( pakket ).
ENDCASE.
ENDLOOP.
LOOP AT it_vrachtwagens INTO vrachtwagen.
vrachtwagen->DisplayLading( ).
ENDLOOP.
I've written code to fill the trucks with packages and added the trucks to the internal table over which I loop. My guess is that the write method in the CVrachtwagen class implementation can't write to the screen, because the program is still running the loop?
The system variable SY-INDEX is not set inside a LOOP AT loop, you need to replace it with SY-TABIX inside your loops over it_vrachtwagens and it_pakket.
From SAP's documentation (not too helpful):
sy-index - Loop index. In DO and WHILE loops, contains the number of previous loop passes, including the current pass.
sy-tabix - Row number in the table index of an internal table. Contains the last row accessed using a primary or secondary table index. Is set to 0 when accessed using a hash algorithm.

Data Type Encompassing Two Sum Types?

Given these 2 sum types:
data Foo = A Int | B String
data Bar = C Int | D String
I'd like to define a function that returns Either (Foo or Bar) String.
So, I attempted to make:
data Higher = Foo | Bar
But it failed to compile:
*ADT> :r
Type checking ./ADT.idr
ADT.idr:3:6:Main.Foo is already defined
ADT.idr:4:6:Main.Bar is already defined
How can I create a Higher data type, which consists of Foo or Bar?
Yes you can indeed!
data Foo = A Int | B String
data Bar = C Int | D String
data Higher : Type where
InjFoo : Foo -> Higher
InjBar : Bar -> Higher
Now you can do InjFoo (B "Hello") or InjBar (C 5).

How to create words within a Forth definition

I'm using Gforth, and I want to create a word in a definition. In the cmd line of Gforth I can type:
create foo
ok
Or more specifically, I defined an array function that expects a size on the stack and creates a word with the address to that array:
: array ( n -- ) ( i -- addr)
create cells allot
does> cells + ;
So if I type 10 array foo I can then use foo later.
But if I were to write 10 array foo within another definition it gives me a compilation error. I've tried replacing foo with s" foo" which compiles, but it blows up at run time, saying:
Attempt to use zero-length string as a name
Is there a way to do this?
One way to do it in gforth:
: bar 10 s" foo" ['] array execute-parsing ;
Other implementations do it differently, e.g. http://pfe.sourceforge.net/words/w-header-015.html
It's not easy to do in Standard Forth, but this may be good enough:
: bar 10 s" array foo" evaluate ;
I guess most of what you want to do can be done by defining words, i.e. using create ... does> ... This allows you to define a word with specialized behaviour.
E.g.:
: 2const create , , does> 2# ;
can be used to create double constants like 2 3 2const a-double (that stashes 2 and 3 away in a-double) and then a-double pushes two values (2 3).

Address of element within a structure from elf executable

Is it possible to obtain the address of an element within a structure from an ELF executable not compile for debug?
Example, given the following code:
typedef struct {
int tokyo;
int paris;
int london;
}cities;
cities places;
Both nm and readelf give the start address of the variable 'places', and readelf also gives the sizeof:
Num: Value Size Type Bind Vis Ndx Name
1994983: d0003ae8 12 OBJECT GLOBAL DEFAULT 23 cities
However what I need is the address of each element within the structure. So from above what I want is:
d0003ae8 cities.tokyo
d0003aec cities.paris
d0003af0 cities.london
My only route at present is to compile with dwarf2 debug info, use readelf (-wliao) to dump out the .debug_info section, and then parse the type tree from a DW_TAG_variable adding up base_type sizes. Example readelf:
<1><e00b>: Abbrev Number: 5 (DW_TAG_structure_type)
DW_AT_byte_size : 12
DW_AT_decl_file : 3
DW_AT_decl_line : 25
<2><e013>: Abbrev Number: 6 (DW_TAG_member)
DW_AT_name : tokyo
DW_AT_decl_file : 3
DW_AT_decl_line : 15
DW_AT_type : <df04>
<2><e02e>: Abbrev Number: 6 (DW_TAG_member)
DW_AT_name : paris
DW_AT_decl_file : 3
DW_AT_decl_line : 16
DW_AT_type : <df04>
<2><e02e>: Abbrev Number: 6 (DW_TAG_member)
DW_AT_name : london
DW_AT_decl_file : 3
DW_AT_decl_line : 16
DW_AT_type : <df04>
I need to find a way of doing this without access to the source code, and with debug info turned off..
Any help or pointers appreciated.
Thanks,
Chris
No, there is no way to do this. ELF alone does not describe types or offsets.
If you know the types of the fields of the structure and the ABI of the architecture for which the object is built, you can recreate the layout.