Single procedure with universal structure type as parameter

Just starting out? Need help? Post your questions and find answers here.
eNano
User
User
Posts: 13
Joined: Wed Jun 05, 2024 4:48 pm

Single procedure with universal structure type as parameter

Post 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)

User avatar
jacdelad
Addict
Addict
Posts: 1993
Joined: Wed Feb 03, 2021 12:46 pm
Location: Riesa

Re: Single procedure with universal structure type as parameter

Post 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.
Good morning, that's a nice tnetennba!

PureBasic 6.21/Windows 11 x64/Ryzen 7900X/32GB RAM/3TB SSD
Synology DS1821+/DX517, 130.9TB+50.8TB+2TB SSD
User avatar
idle
Always Here
Always Here
Posts: 5836
Joined: Fri Sep 21, 2007 5:52 am
Location: New Zealand

Re: Single procedure with universal structure type as parameter

Post 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)

User avatar
NicTheQuick
Addict
Addict
Posts: 1504
Joined: Sun Jun 22, 2003 7:43 pm
Location: Germany, Saarbrücken
Contact:

Re: Single procedure with universal structure type as parameter

Post 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.
The english grammar is freeware, you can use it freely - But it's not Open Source, i.e. you can not change it or publish it in altered way.
benubi
Enthusiast
Enthusiast
Posts: 215
Joined: Tue Mar 29, 2005 4:01 pm

Re: Single procedure with universal structure type as parameter

Post 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
eNano
User
User
Posts: 13
Joined: Wed Jun 05, 2024 4:48 pm

Re: Single procedure with universal structure type as parameter

Post 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
eNano
User
User
Posts: 13
Joined: Wed Jun 05, 2024 4:48 pm

Re: Single procedure with universal structure type as parameter

Post 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()

User avatar
idle
Always Here
Always Here
Posts: 5836
Joined: Fri Sep 21, 2007 5:52 am
Location: New Zealand

Re: Single procedure with universal structure type as parameter

Post 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.
Post Reply