ProcedureReturn returning more than one value

Got an idea for enhancing PureBasic? New command(s) you'd like to see?
User avatar
charvista
Addict
Addict
Posts: 949
Joined: Tue Sep 23, 2008 11:38 pm
Location: Belgium

ProcedureReturn returning more than one value

Post by charvista »

Returning more than one value can be very handy.
I saw in another programming language this code:

Code: Select all

  def Geo::dec2dms(dec)
    s = dec * 3600
    d = (s / 3600).floor
    s -= d * 3600
    m = (s / 60).floor
    s -= m * 60
    return d, m, s
  end
Can this be implemented in PureBasic too?
Thanks for thinking about that...
- Windows 11 Home 64-bit
- PureBasic 6.10 LTS (x64)
- 64 Gb RAM
- 13th Gen Intel(R) Core(TM) i9-13900K 3.00 GHz
- 5K monitor with DPI @ 200%
c4s
Addict
Addict
Posts: 1981
Joined: Thu Nov 01, 2007 5:37 pm
Location: Germany

Re: ProcedureReturn returning more than one value

Post by c4s »

I know this could be annoying but try using an structure for that.
If any of you native English speakers have any suggestions for the above text, please let me know (via PM). Thanks!
User avatar
TomS
Enthusiast
Enthusiast
Posts: 342
Joined: Sun Mar 18, 2007 2:26 pm
Location: Munich, Germany

Re: ProcedureReturn returning more than one value

Post by TomS »

c4s wrote:I know this could be annoying but try using an structure for that.
How?

Code: Select all

Structure myStruct
	minutes.i
	hours.i
EndStructure  

Procedure bla(a,b)
	Protected time.myStruct
	time\hours = a
	time\minutes = b
	ProcedureReturn time
EndProcedure

Debug bla\minutes ; Error in this line
=> The variable has a structure

Code: Select all

Structure myStruct
	minutes.i
	hours.i
EndStructure  

Procedure.myStruct bla(a,b) ; Error in this line
	Protected time.myStruct
	time\hours = a
	time\minutes = b
	ProcedureReturn time
EndProcedure

Debug bla\minutes 
=> A structure can't be used with ProcedureReturn
Fred
Administrator
Administrator
Posts: 18162
Joined: Fri May 17, 2002 4:39 pm
Location: France
Contact:

Re: ProcedureReturn returning more than one value

Post by Fred »

Try this (not tested):

Code: Select all

Structure myStruct
   minutes.i
   hours.i
EndStructure 

Procedure bla(a,b, *result.myStruct)
   *result\hours = a
   *result\minutes = b
EndProcedure

bla(10, 20, @minutes.myStruct)
Debug minutes\hours
Debug minutes\minutes
User avatar
TomS
Enthusiast
Enthusiast
Posts: 342
Joined: Sun Mar 18, 2007 2:26 pm
Location: Munich, Germany

Re: ProcedureReturn returning more than one value

Post by TomS »

Thank you.
I know this method and similar ones, but it's just not like PB. It looks more like C++
But it's an OK workaround, I guess.
User avatar
blueznl
PureBasic Expert
PureBasic Expert
Posts: 6166
Joined: Sat May 17, 2003 11:31 am
Contact:

Re: ProcedureReturn returning more than one value

Post by blueznl »

Fred, as you're reading this topic anyway :-) ...

Would there ever be a change of procedures returning structures, or procedures returning multiple variables? It would be a great enhancement to the language, and clearly distinguish it from its lesser brethern :-)
( PB6.00 LTS Win11 x64 Asrock AB350 Pro4 Ryzen 5 3600 32GB GTX1060 6GB)
( The path to enlightenment and the PureBasic Survival Guide right here... )
Little John
Addict
Addict
Posts: 4779
Joined: Thu Jun 07, 2007 3:25 pm
Location: Berlin, Germany

Re: ProcedureReturn returning more than one value

Post by Little John »

I just want to mention that it's also possible for a procedure, to return a pointer to a static structure inside the procedure. Here is a modification of Fred's example:

Code: Select all

Structure myStruct
   hours.i
   minutes.i
EndStructure

Procedure bla (a, b)
   Static result.myStruct
   
   result\hours = a
   result\minutes = b
   ProcedureReturn @result
EndProcedure

Define *time.MyStruct

*time = bla(10, 20)
Debug *time\hours
Debug *time\minutes
Regards, Little John
User avatar
TomS
Enthusiast
Enthusiast
Posts: 342
Joined: Sun Mar 18, 2007 2:26 pm
Location: Munich, Germany

Re: ProcedureReturn returning more than one value

Post by TomS »

It has to be static. I don't know why, but otherwise I get a very high number (unknowing me guesses it is the pointer address?) and 0 as debugger-ouput.
But since a pointer to the static content is returned, every call of the procedure overrides everything, and every pointer is the same after all.

Code: Select all

Structure myStruct
   hours.i
   minutes.i
EndStructure

Procedure bla (a, b)
   Static result.myStruct
   
   result\hours = a
   result\minutes = b
   ProcedureReturn @result
EndProcedure

Define *time.MyStruct

*time = bla(10, 20)
*blub = bla(13,30)
Debug *time\hours ;With normal returns this would still be 10, but it is 13 now.
Debug *time\minutes
Little John
Addict
Addict
Posts: 4779
Joined: Thu Jun 07, 2007 3:25 pm
Location: Berlin, Germany

Re: ProcedureReturn returning more than one value

Post by Little John »

TomS wrote:It has to be static.
Yes, I did write that. (Global or Shared would work as well.)
A local variable in a procedure does not exist anymore after the procedure has finished.

Regards, Little John
User avatar
charvista
Addict
Addict
Posts: 949
Joined: Tue Sep 23, 2008 11:38 pm
Location: Belgium

Re: ProcedureReturn returning more than one value

Post by charvista »

We can also do it by adding the needed pointers-variables as parameters:

Code: Select all

Procedure.d zDec2Dms(Dec.d,*D.integer,*M.integer,*S.integer)
    Seconds.d=Dec*3600
    Degrees.d=Int(Seconds/3600)
    Seconds-Degrees*3600
    Minutes.i=Int(Seconds/60)
    Seconds-Minutes*60
    *D\i=Int(Degrees)
    *M\i=Int(Minutes)
    *S\i=Int(Seconds)
EndProcedure
However, my wish here is just about returning more than one variable from a simple procedure without complications like pointers, structures,....
so I could export D, M, S easily.
I see that Blueznl is seconding this wish. (thanks!)
- Windows 11 Home 64-bit
- PureBasic 6.10 LTS (x64)
- 64 Gb RAM
- 13th Gen Intel(R) Core(TM) i9-13900K 3.00 GHz
- 5K monitor with DPI @ 200%
User avatar
TomS
Enthusiast
Enthusiast
Posts: 342
Joined: Sun Mar 18, 2007 2:26 pm
Location: Munich, Germany

Re: ProcedureReturn returning more than one value

Post by TomS »

Little John wrote:A local variable in a procedure does not exist anymore after the procedure has finished.
Thus the feature request for structured returns ;)

I was aware of that method, too, but I dumped it, since it is only useful for one-time-calls like InitMyFramework().
Though Init-Functions mostly (always?) return only True or False or maybe ID or False^^
DarkDragon
Addict
Addict
Posts: 2344
Joined: Mon Jun 02, 2003 9:16 am
Location: Germany
Contact:

Re: ProcedureReturn returning more than one value

Post by DarkDragon »

Little John wrote:
TomS wrote:It has to be static.
Yes, I did write that. (Global or Shared would work as well.)
But you should also mention that this is not threadsafe. For threadsafety you can use this:

Code: Select all

Structure TheStructure
  a.i
  b.i
  c.i
EndStructure

Procedure.i ThreadSafeMultiReturn()
  Protected *Result.TheStructure
  
  *Result = AllocateMemory(SizeOf(TheStructure))
  If *Result
    *Result\a = 10
    *Result\b = 20
    *Result\c = 30
    ProcedureReturn *Result
  EndIf
  
  Debug "Not enough memory?"
  ProcedureReturn #Null
EndProcedure

*Result.TheStructure = ThreadSafeMultiReturn()

If *Result <> #Null
  Debug *Result\a
  Debug *Result\b
  Debug *Result\c
  FreeMemory(*Result)
EndIf
[EDIT]
Or use the new Threaded keyword.
Last edited by DarkDragon on Tue Aug 31, 2010 6:11 pm, edited 1 time in total.
bye,
Daniel
User avatar
TomS
Enthusiast
Enthusiast
Posts: 342
Joined: Sun Mar 18, 2007 2:26 pm
Location: Munich, Germany

Re: ProcedureReturn returning more than one value

Post by TomS »

Ok.
Some people want this feature in everyday coding, which is fine. I'd like that too.
Others want to offer includes with commands that 'feel' like native PB-Commands.

If somebody is looking for that, here is what I do.
I use a global array for my objects.

Code: Select all

Structure Object
	size.i
	state.i
EndStructure

Global Dim id.Object(1)

Procedure CreateObject(size.i, state.i)
	Protected count.i = ArraySize(id())-1
	
	id(count)\size = size
	id(count)\state = state
	
	ReDim id(ArraySize(id())+1)
	
	ProcedureReturn count	
EndProcedure

Procedure SetObjectState(state.i, id.i)	
	id(id)\state = state		
EndProcedure 

Procedure GetObjectState(id.i)	
	ProcedureReturn id(id)\state	
EndProcedure

c = CreateObject(1, 2)
d = CreateObject(1, 4)
SetObjectState(78, d)

Debug GetObjectState(c)
Debug GetObjectState(d)
End
DarkDragon
Addict
Addict
Posts: 2344
Joined: Mon Jun 02, 2003 9:16 am
Location: Germany
Contact:

Re: ProcedureReturn returning more than one value

Post by DarkDragon »

An example with "Threaded" keyword for threadsafety:

Code: Select all

Structure TheStructure
  a.i
  b.i
  c.i
EndStructure

Threaded Result.TheStructure

Procedure.i ThreadSafeMultiReturn()
  Result\a = 10
  Result\b = 20
  Result\c = 30
  ProcedureReturn @Result
EndProcedure

*Result.TheStructure = ThreadSafeMultiReturn()

If *Result
  Debug Result\a
  Debug Result\b
  Debug Result\c
Else
  Debug "Failed?"
EndIf
But notice that you can't call ThreadSafeMultiReturn a second time inside the same Thread without loosing the old result and its just leading to bugs if you return the pointer as you might not remember the first part of my sentence.
bye,
Daniel
jamirokwai
Enthusiast
Enthusiast
Posts: 796
Joined: Tue May 20, 2008 2:12 am
Location: Cologne, Germany
Contact:

Re: ProcedureReturn returning more than one value

Post by jamirokwai »

charvista wrote:Returning more than one value can be very handy.
I saw in another programming language this code:

Code: Select all

  def Geo::dec2dms(dec)
    s = dec * 3600
    d = (s / 3600).floor
    s -= d * 3600
    m = (s / 60).floor
    s -= m * 60
    return d, m, s
  end
Can this be implemented in PureBasic too?
Thanks for thinking about that...
Would be great to have a ProcedureReturn with multiple values :-)

I encountered a problem, where I like to have a String and two Integers given back from a function.
My approach was to use String + "|" + Str(i1) + "|" + Str(i2) and to use StringField to get back the info.
But you couldn't use this when your need Full Speed... :-O

Maybe like this!? Would be a great enhancement!!!

Procedure xyz(a,b,c)
return a,b,c
EndProcedure

(x,y,z) = xyz(a,b,c)
Regards,
JamiroKwai
Post Reply