Page 1 of 1
Single procedure with universal structure type as parameter
Posted: Fri Jul 19, 2024 10:41 pm
by eNano
Hi,
I'm trying to do a single function that takes a single "non specific type" pointer to handle parameters with different structures
Is it safe to use something like this? I'm not expert about memory stuffs
Code: Select all
#TYPE_RECTANGLE = 1
#TYPE_CIRCLE = 2
#TYPE_POLYGON = 3
Structure rectangleData
Width.f
Height.f
EndStructure
Structure CircleData
Radius.f
EndStructure
Structure PolygonData
VertsCount.i
Length.f
EndStructure
Structure rectangleSTRUCT
nodeType.i
properties.rectangleData
EndStructure
Structure CircleSTRUCT
nodeType.i
properties.CircleData
EndStructure
Structure PolygonSTRUCT
nodeType.i
properties.PolygonData
EndStructure
Procedure doSomething ( memoryAddress.i )
strucType = PeekI(memoryAddress)
If strucType = #TYPE_RECTANGLE
*rect.rectangleData = memoryAddress + 4
Debug ("RECTANGLE HEIGHT: " + *rect\Height)
Debug ("RECTANLE WIDTH: " + *rect\Width )
EndIf
If strucType = #TYPE_CIRCLE
*circ.CircleData = memoryAddress + 4
Debug ("CIRCLE RADIUS: " + *circ\Radius)
EndIf
If strucType = #TYPE_POLYGON
*poly.PolygonData = memoryAddress + 4
Debug ("POLY VERTS COUNT: " + *poly\VertsCount )
Debug ("POLY LENGTH: " + *poly\Length)
EndIf
EndProcedure
Rectangle.rectangleSTRUCT
Rectangle\nodeType = #TYPE_RECTANGLE
Rectangle\properties\Height = 55
Rectangle\properties\Width = 33
Circle.CircleSTRUCT
Circle\nodeType = #TYPE_CIRCLE
Circle\properties\Radius = 24
Polygon.PolygonSTRUCT
Polygon\nodeType = #TYPE_POLYGON
Polygon\properties\VertsCount = 88
Polygon\properties\Length = 12
ptr = @Rectangle
doSomething (ptr)
ptr = @Circle
doSomething (ptr)
ptr = @Polygon
doSomething (ptr)
Re: Single procedure with universal structure type as parameter
Posted: Fri Jul 19, 2024 10:47 pm
by jacdelad
I guess that's how you can do it. On the other hand you could create a "universal" structure with enough variables and some unions.
Re: Single procedure with universal structure type as parameter
Posted: Sat Jul 20, 2024 2:51 am
by idle
Without knowing what the end goal is if you don't mind the overhead of a wrapper structure
using a structure union is a much simpler approach and the size is fixed.
Code: Select all
#TYPE_RECTANGLE = 1
#TYPE_CIRCLE = 2
#TYPE_POLYGON = 3
Structure rectangleData
Width.f
Height.f
EndStructure
Structure CircleData
Radius.f
EndStructure
Structure PolygonData
VertsCount.i
Length.f
EndStructure
Structure AnyStruct
nodeType.i
StructureUnion
rect.rectangleData
circ.CircleData
poly.PolygonData
EndStructureUnion
EndStructure
Procedure doSomething(*st.AnyStruct)
Select *st\nodeType
Case #TYPE_RECTANGLE
Debug ("RECTANGLE HEIGHT: " + *st\rect\Height)
Debug ("RECTANLE WIDTH: " + *st\rect\Width )
Case #TYPE_CIRCLE
Debug ("CIRCLE RADIUS: " + *st\circ\Radius)
Case #TYPE_POLYGON
Debug ("POLY VERTS COUNT: " + *st\poly\VertsCount)
Debug ("POLY LENGTH: " + *st\poly\Length)
EndSelect
EndProcedure
Rectangle.AnyStruct
Rectangle\nodeType = #TYPE_RECTANGLE
Rectangle\rect\Height = 55
Rectangle\rect\Width = 33
Circle.AnyStruct
Circle\nodeType = #TYPE_CIRCLE
Circle\circ\Radius = 24
Polygon.AnyStruct
Polygon\nodeType = #TYPE_POLYGON
Polygon\poly\VertsCount = 88
Polygon\poly\Length = 12
doSomething (@Rectangle)
doSomething (@Circle)
doSomething (@Polygon)
Re: Single procedure with universal structure type as parameter
Posted: Sat Jul 20, 2024 10:45 am
by NicTheQuick
This is basically one step before going OOP. With Interfaces you could do something very similar but instead of having a type that you compare with a select statement you have pointers to the corresponding procedures for a certain type. With that you don't need to branch.
Re: Single procedure with universal structure type as parameter
Posted: Sat Jul 20, 2024 5:14 pm
by benubi
There are two ways you can do this easily.
First is to add a type parameter for your structure type.
Code: Select all
; add the type as a parameter
Procedure DoSometing(*ptr, Type)
Protected *rectangleData.rectangleData
Protected *CircleData.CircleData
Protected *PolygonData.PolygonData
Select Type
Case #TYPE_RECTANGLE
*rectangleData = *ptr
; ...
Case #TYPE_CIRCLE
*CircleData = *ptr
; ...
Case #TYPE_POLYGON
*PolygonData = *ptr
; ...
EndSelect
EndProcedure
Second is to embed the type at the beginning of the structure (like in idle's example).
Using and extending StructureUnion like in idle's example and as suggested by jacdelad is the best idea because it will save you variables as compared to when doing it with Extends (structure inheritance), and the source code will be better (human) readable and easier to debug. I would propose you follow idle's example but this is for completeness:
Code: Select all
; embed the type into structure
Structure Common_Node_Header
nodeType.i
EndStructure
Structure rectangleData Extends Common_Node_Header
Width.f
Height.f
EndStructure
Structure CircleData Extends Common_Node_Header
Radius.f
EndStructure
Structure PolygonData Extends Common_Node_Header
VertsCount.i
Length.f
EndStructure
Procedure doSomething(*Node.Common_Node_Header)
Protected *rectangleData.rectangleData
Protected *CircleData.CircleData
Protected *PolygonData.PolygonData ; <--- needs 3 additional pointers in memory/stack, most remain unused
Select *Node\nodeType
Select Type
Case #TYPE_RECTANGLE
*rectangleData = *Node; needs to be set
; ...
Case #TYPE_CIRCLE
; ...
Case #TYPE_POLYGON
; ...
EndSelect
EndSelect
EndProcedure
Re: Single procedure with universal structure type as parameter
Posted: Sat Jul 20, 2024 6:03 pm
by eNano
Thanks a lot for sharing your knowledge! you all gave me great ideas to study, this is still a bit confusing for me but the examples are very useful.
I'm trying to do a simple 2d vector drawing application and I need to think about how to handle the nodes and how to make improvements in some kind of modular way
Re: Single procedure with universal structure type as parameter
Posted: Fri Sep 13, 2024 7:30 pm
by eNano
Hi, I keep testing things about this subject and I have another doubt, I need to do a single function to update several kind of structures, I'm thinking about making a program with some kind of plugin system.
Is this concept going to generate some internal problem or could it be ok to be used?
Code: Select all
;MAIN STRUCTURE TO MAKE A LIST OF ALL KIND OF NODES
Structure node
*anyStructurePointer
*updateMethodPTR
EndStructure
Global NewList Nodes.node()
Global *currentNode
;ANY KIND OF STRUCTURE DEFINED AT ANY TIME REGISTERED IN A MAIN LIST
;___________________________________
Structure circle
selected.i
ID.i
EndStructure
Procedure updateCircle()
Debug "Updating Circle Status"
*currentCircle.Circle = *currentNode
Debug "ID: " + *currentCircle\ID
Debug "Selected: " + *currentCircle\selected
EndProcedure
Global NewList circles.Circle()
Procedure newCircle()
AddElement( circles() )
circles()\selected = 1
circles()\ID = ListSize(circles())
AddElement(nodes())
nodes()\anyStructurePointer = @circles()
nodes()\updateMethodPTR = @updateCircle()
EndProcedure
;___________________________________
Structure rectangle
selected.i
ID.i
EndStructure
Procedure updateRectangle()
Debug "Updating Rectangle Status"
*currentRectangle.rectangle = *currentNode
Debug "ID: " + *currentRectangle\ID
Debug "Selected: " + *currentRectangle\selected
EndProcedure
Global NewList rectangles.rectangle()
Procedure newRectangle()
AddElement(rectangles())
rectangles()\selected = 1
rectangles()\ID = ListSize(rectangles())
AddElement(nodes())
nodes()\anyStructurePointer = @rectangles()
nodes()\updateMethodPTR = @updateRectangle()
EndProcedure
;___________________________________
Structure triangle
selected.i
ID.i
EndStructure
Procedure updateTriangle()
Debug "Updating Triangle Status"
*currentTriangle.Triangle = *currentNode
Debug "ID: " + *currentTriangle\ID
Debug "Selected: " + *currentTriangle\selected
EndProcedure
Global NewList triangles.triangle()
Procedure newTriangle()
AddElement(triangles())
triangles()\selected = -1
triangles()\ID = ListSize(triangles())
AddElement(nodes())
nodes()\anyStructurePointer = @triangles()
nodes()\updateMethodPTR = @updateTriangle()
EndProcedure
;___________________________________
Prototype.f updateNode( )
Global updater.updateNode
;FUNCTION TO RUN ANY KIND OF PROCEDURE ACCORDING TO THE TYPE OF THE SELECTED STRUCTURE
Procedure updateAllCreatedNodes()
ForEach nodes()
*currentNode = nodes()\anyStructurePointer; GET THE CURRENT NODE INSTANCE
updater = nodes()\updateMethodPTR; REDEFINE DE UPDATER FUNCTION TO WORK WITH THE CURRENT SELECTION
updater( )
Debug ""
Next
EndProcedure
newCircle()
newRectangle()
newTriangle()
newRectangle()
newCircle()
newCircle()
newTriangle()
updateAllCreatedNodes()
Re: Single procedure with universal structure type as parameter
Posted: Fri Sep 13, 2024 8:18 pm
by idle
As long as your main program knows what the structures are it's easily done
You can use a pointer and cast it as nessersary given a user defined type.
Then use a select to call the appropriate functions.