Functions Returning Strings?


TrevorBradley

Active Member
Joined
Nov 6, 2007
Messages
732
New problem, this time specific to Fenix (0.92) and not the GP2X interpreter.

I can't seem to get a function to return a String. I define the function type, try returning a string "foo", and I get back "14". It looks like an int pointer to something. If I run the function over again it seems to increment...

I'm trying to create a function that takes a float and cuts it down to something more readable (10.00001 -> 10, 9.145252351 -> 9.14)

Any ideas on how to do this? Thanks in advance.
 
Try this and see if it works fast enough for your purposes:

CODE
float precision = 100;

float x = 9.145252351;

float newX = (int)x + (int)((x - (int)x) * precision) / precision;


Hopefully it works :)
 
It works, but so did my String function. Both appear to return garbage, even though I've declared the function to return String or float. (If I leave the type undeclared it appears to return int.

I didn't know you could cast variables that way though in Fenix.. thanks, I learned something new.

Is it possible the function variables being declared as private get deallocated after the function is run?

EDIT: Well, I can get around this... Here's my broken code:


This code breaks and returns an integer.

CODE
Function float nice_float(float f)
Private
int decimal_pos;
float myfloat;
Begin
decimal_pos = find(f, ".");
myfloat = (f*pow(10,decimal_pos+2));
myfloat = (int)myfloat;
myfloat = (myfloat/pow(10,decimal_pos+2));

return myfloat;
End;





This works because it doesn't return a float. Rather it modifies the parameter f. Even adding "return f;" to the end of this code block doesn't work.

CODE
Function nice_float(float f)
Private
int decimal_pos;
Begin
decimal_pos = find(f, ".");
f = (f*pow(10,decimal_pos+2));
f = (int)f;
f = (f/pow(10,decimal_pos+2));
End;





I still need an answer to my original question. How does a function return a non-int? Why does this program return "1"?

CODE

Program example;
Begin

Repeat
write(0,0,0,0,hello_world());
frame;
Until(key(_ESC))

End

Function String hello_world()
Begin
return "Hello World!";
End
 
what happens if you first assign what the function returns to a variable of that type, and then write that to the screen?
 
The order of functions/processes in your .prg file matters when it comes to returning strings (and it also matters for using public variables). Fenix defaults all functions to return ints and any function coming before another function will assume the latter is returning an int. So, you would need to have the function that returns the string before the function/process that calls it in your code so it is known this function returns a string - however, instead of messing around with the order of functions in your code you should declare/prototype the function that returns the string, so the return type will be known before the function is called.

Trevor's example up a bit should work like this:

CODE

Program example;

Declare Function String hello_world()
End

Begin
write(0,0,0,0,hello_world());
Repeat
frame;
Until(key(_ESC))
End

Function String hello_world()
Begin
return "Hello World!";
End


(PS. Writing ";"s after each end is unnecessary. It seems to be an oddity that arose on this forum, as a lot of people on here seem to do it. :p)
(PS 2. When Trevor says "Both appear to return garbage, even though I've declared the function to return String or float." I am assuming he meant he wrote out the function return type instead of using the declare statement because I'm not seeing any declares in his example code.)
(PS 3. Took your write() statement out of the loop, shouldn't be in there as far as I can see.)
 
Rincewind said:
The order of functions/processes in your .prg file matters when it comes to returning strings (and it also matters for using public variables). Fenix defaults all functions to return ints and any function coming before another function will assume the latter is returning an int. So, you would need to have the function that returns the string before the function/process that calls it in your code so it is known this function returns a string - however, instead of messing around with the order of functions in your code you should declare/prototype the function that returns the string, so the return type will be known before the function is called.


Yup, I'm not declaring my functions, and this is the problem.

Hmm, placing the functions first also works.

I really don't like splitting the functions up, having a declare section at the top, and the function at the bottom of the file below the main process. If it were just a simple declare header, I'd be ok with some duplication (Declare Function, and then later Function), and I can understand the declaration of public variables, but I have no clue why the function's private variables need to be in the Declare statement. They should be with the function no matter what.

I think I'm going to move to simply placing my functions at the start of the file. It's a lot cleaner and clearer that way.

Thanks for your help!!!
 
Last edited by a moderator:
I agree it's all a bit messy, I would have preferred for this whole declaration thing to be done internally by the compiler so we programmers don't have to get our hands dirty, but apparantly it's too hard for the current programmer of Fenix (Juan) to make it an internal process.

Trevor said:
I think I'm going to move to simply placing my functions at the start of the file. It's a lot cleaner and clearer that way.
Note that it can be an order issue between multiple functions/processes that make calls to each other too, not necessarily the 'program' and a function. The program block is basically a process. So you would need a distinct order between all of your processes/functions.

You are going to run in trouble with keeping a manual order of processes eventually as order priorities can be entangled. Let's say you have 2 functions that make calls to eachother and each returns a string - there's no way to do this without using Declare. Another example would be having two functions where one function calls the other function that returns a string, while the latter function uses a public variable defined in the first function. You're not going to solve that with a certain order. :)

Trevor said:
I have no clue why the function's private variables need to be in the Declare statement. They should be with the function no matter what.
You don't have to put the private variables in the declare block when you define them in the actual process/function. You either have to define a variable in the declare block or in the process/function.

Happy coding.
 
Last edited by a moderator:
Rincewind said:
Trevor said:
define a variable in the function. All the Public and Private variables have to move up to the Define block.

This code, for instance, won't compile. I get an error that says it expects "Begin" where it sees "Private".

CODE

Program example;

Declare Function String hello_world()
End

Begin
write(0,0,0,0,hello_world());

Repeat
frame;
Until(key(_ESC))
End

Function String hello_world()
Private
String s;
End
Begin
s = "Hello World";
return s;
End

If you move "Private s;" into the Declare block it compiles and runs just fine.

If you could put the private variables down in the function block, I think I'd be a bit happier using the Declare Function block.

And I totally understand on the recursive functions and function order. But not even the crazy program I'm writing right now is that recursive. :)
 
Last edited by a moderator:
Rincewind said:
Trevor said:
I have no clue why the function's private variables need to be in the Declare statement. They should be with the function no matter what.
You don't have to put the private variables in the declare block when you define them in the actual process/function. You either have to define a variable in the declare block or in the process/function.

In 0.92a this was an issue I believe and was fixed in 0.93.

Trevor said:
Is it possible the function variables being declared as private get deallocated after the function is run?
Of course, variables owned by a process/function get deallocated when it dies. What you could do is:
CODE

Function int bla(_mytype* mytype)
Begin
//blabla
End
And pass this function a mytype variable pointer to which it can make changes.

Rincewind said:
I agree it's all a bit messy, I would have preferred for this whole declaration thing to be done internally by the compiler so we programmers don't have to get our hands dirty, but apparantly it's too hard for the current programmer of Fenix (Juan) to make it an internal process.
C/C++ is the same, also when it comes to memory being deallocated when the block becomes out of scope (like when a process gets killed). Personally I would have liked it better if Fenix didn't default things to int nor that it would prototype at all. Luckily the latter is made optionally in Bennu, as you can select oldstyle prototyping or that the programmer needs to do it himself.
 
Last edited by a moderator:
Aha! I assume that basic types String, int, float, etc, are the only safe thing to pass back from and to a function?

Oooooooooooooooooo... I think I know what's going on... I've been spoiled by 11 years of Java prorgamming. It's been about 14 years since I programmed any C.

Parameters for C, C++, and Fenix functions can only be basic types (int, float, etc) or pointers.. String is an exception, but it's really a pointer too.

This works:

CODE
Program example;

Type _mytype
String value;
End;

Function _mytype* hello_world()
Private _mytype* s1;
Begin
s1=alloc(sizeof(_mytype)); //memory must be allocated or else it is freed with the function.
s1.value = "Hello World";
return s1;
End

Private
_mytype* mystring;
End

Begin
mystring = hello_world();
write(0,0,0,0,"Value >"+mystring.value+"<");
Repeat
frame;
Until(key(_ESC))
End


Awesome Awesome Awesome... this answers all my questions (for now, and I really hope for a while).

Thank you so much!

... goes off to tinker ...
 
Trevor Bradley said:
Parameters for C, C++, and Fenix functions can only be basic types (int, float, etc) or pointers.. String is an exception, but it's really a pointer too.
Yes that's about right. Internally a String is an identifier to an element in a char* array, pointing to the actual string (char array).

You could also return _mytype instead of _mytype* and do
CODE

return *s1;


because internally s1 is just a pointer.
Unfortunately, this wont help at all as we still would need a variable of type _mytype* to put the value in, as otherwise it will nag about 'Struct required (")")'...yeah I know, when it comes to types Fenix is not all that. But just use pointers and you'll be fine.

One note for the road:
For variable c of type _mytype applies:
c == &c
For variable c of type _mytype* applies:
*c == c
This only works for userdefined variables and not for others, which is the logical way, as it's total nonsense that this works, but I guess these weird things will be ironed out in time.
 
Last edited by a moderator:
Rincewind said:
I agree it's all a bit messy, I would have preferred for this whole declaration thing to be done internally by the compiler so we programmers don't have to get our hands dirty, but apparantly it's too hard for the current programmer of Fenix (Juan) to make it an internal process.

Trevor said:
I think I'm going to move to simply placing my functions at the start of the file. It's a lot cleaner and clearer that way.
Note that it can be an order issue between multiple functions/processes that make calls to each other too, not necessarily the 'program' and a function. The program block is basically a process. So you would need a distinct order between all of your processes/functions.

You are going to run in trouble with keeping a manual order of processes eventually as order priorities can be entangled. Let's say you have 2 functions that make calls to eachother and each returns a string - there's no way to do this without using Declare. Another example would be having two functions where one function calls the other function that returns a string, while the latter function uses a public variable defined in the first function. You're not going to solve that with a certain order. :)
I hate to do this, but I've gone back to the function ordering and removed all my declared functions....

I had very nicely declared functions, and fxi and fxc were all happy, but I managed to hit some sort of combination that caused Flamebird to crash when my prg file was opened. It had to do with a combination of declared types, and functions that returned pointers, and Flamebirds analyzing the file before displaying it. I've sent off a bug report on their sourceforge.

I tried switching to ConTEXT last night, but I don't like how poorly it's integrated with fxc. I like a bit more feedback if I'm getting errors... :(

EDIT: Flamebird peeved me off even more and I'm back to ConTEXT now. :|
 
Last edited by a moderator:
I don't recommend FlameBird as it's buggy and annoying to work with, to me anyway. I do use ConTEXT for Fenix, because it's a nice editor and does what I want, though the lack of a profiler and other handy stuff is pretty uncool. I wouldn't recommend adapting code to an editor, as that only reduces the functionality of the language itself, so for now I'd say use ConTEXT until this guy comes up with a Windows release.
 
Last edited by a moderator:
Trevor said:
I tried switching to ConTEXT last night, but I don't like how poorly it's integrated with fxc. I like a bit more feedback if I'm getting errors...
You can catch FXC's output in the ConTEXT "output console" window, but since ConTEXT is a universal editor as opposed to Flamebird you will have to set this up yourself. Sandman wrote some nice batch files for it, which you can get together with instructions on how to set it up from the Fenix wiki.

I also use ConTEXT, it's a fine editor. :)
 
Last edited by a moderator:
I dont really like the declare stuff of the newer Fenix versions,
I would have used something like

CODE
process bla( string pointer text )
begin
*text = "blablabla";
end;
 
Back
Top