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.