1. Konstantin Goldobin
  2. PowerBuilder
  3. Thursday, 18 April 2024 12:29 PM UTC

Hello,

I've stumbled upon this phenomenon while writing tests with PBUnit. For illustration purposes, I isolated it as follows.

Create two global functions:

global function integer f_set_string (integer ai_in, ref string as_out);
if ai_in = 1 then as_out = 'one' else as_out = 'two'

return ai_in

end function

global subroutine f_show_string (string as_string, integer ai_int);
messageBox( 'Result', as_string + ' - ' + string(ai_int))

end subroutine

And then run the following script:

string ls_str

f_show_string( ls_str, f_set_string( 1, ls_str))
f_show_string( ls_str, f_set_string( 2, ls_str))

In my environment (PB 2019 R3 2728), I get this:

   

I must admit, it came as a surprise, and I don't think I've seen this before. Is it documented somewhere and I simply forgot PowerScript basics? :)

Best regards,
Konstantin

Arnd Schmidt Accepted Answer Pending Moderation
  1. Thursday, 18 April 2024 12:50 PM UTC
  2. PowerBuilder
  3. # 1

Hi Konstantin

nice puzzle!

I think you are confused about how stack variables (value vs. reference) work.

hth

Arnd

Comment
There are no comments made yet.
Andreas Mykonios Accepted Answer Pending Moderation
  1. Thursday, 18 April 2024 13:21 PM UTC
  2. PowerBuilder
  3. # 2

Hi.

It looks ok, and of course little confusing.

f_show_string( ls_str, f_set_string( 1, ls_str))

                  ^                        ^
                  |                        |
                copy                      ref

1st call f_show_string copies ls_str. f_set_string is executed later.

2nd call, f_show_string gets ls_str modified. It then calls f_set_string.

I guess your question is if f_set_string should be evaluated before copying ls_string to f_show_string. In my opinion no. What PB does seems to be the right thing. Function f_show_string is called before f_set_string. The copy of ls_string should happen before f_set_string alters it.

In first call of f_set_string ls_str is correctly IMHO passed as "". In second call it is again correctly passed as "one"...

Anyway, those are the dangers of working with pointers... In these case statements may not be very obvious about what they do...

Also, I tested that in c# .net:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace ConsoleApp2
{
    class Program
    {
        static void Main(string[] args)
        {
            string ls_str = "";
            
            f_show_string(ls_str, f_set_string(1, ref ls_str));
            f_show_string(ls_str, f_set_string(2, ref ls_str));

            Console.ReadKey();
        }
        static public int f_set_string(int ai_in, ref string as_out)
        {
            if (ai_in == 1)
                as_out = "one";
            else
                as_out = "two";

            return ai_in;
        }

        static public void f_show_string(string as_string, int ai_int)
        {
            Console.WriteLine("Result: " + as_string + " - " + ai_int.ToString());
        }
    }
}

Here is the result:

Result:  - 1
Result: one - 2

Andreas.

Comment
  1. Arnd Schmidt
  2. Thursday, 18 April 2024 13:37 PM UTC
@Andreas: Cool example!

@Konstantin,

So .. No, you did not forget the PowerScript Basics - only the general basics ;-)
  1. Helpful
  1. Konstantin Goldobin
  2. Thursday, 18 April 2024 14:12 PM UTC
For some reason I assumed that all arguments are evaluated first before passing them to a function call...
  1. Helpful
There are no comments made yet.
Konstantin Goldobin Accepted Answer Pending Moderation
  1. Thursday, 18 April 2024 14:10 PM UTC
  2. PowerBuilder
  3. # 3

I took it a step further and extended f_show_string with the third argument:

global subroutine f_show_string (string as_string, integer ai_int, string as_string_again);
messageBox( 'Result', as_string + ' - ' + string(ai_int) + ' - ' + as_string_again )

end subroutine

So, the calling script changed to:

string ls_str

f_show_string( ls_str, f_set_string( 1, ls_str), ls_str)
f_show_string( ls_str, f_set_string( 2, ls_str), ls_str)

The result:

 

K

Comment
  1. Arnd Schmidt
  2. Thursday, 18 April 2024 16:11 PM UTC
Left to right stuff .... . This is how the PBVM adds values to the stack.

@Andreas: How about C# :-) ?
  1. Helpful
  1. Andreas Mykonios
  2. Friday, 19 April 2024 11:23 AM UTC
See my separate answer for that.

I believe this is more a question to understand how compilers work... We had a book in some university course about making compilers (which wasn't one of my favorite...). Many of those points were explained.

Andreas.
  1. Helpful
  1. Arnd Schmidt
  2. Friday, 19 April 2024 13:00 PM UTC
Ok... let's discuss the World of Compilers and Languages;-)

Who cares about PowerBuilder!
  1. Helpful
There are no comments made yet.
Andreas Mykonios Accepted Answer Pending Moderation
  1. Friday, 19 April 2024 11:19 AM UTC
  2. PowerBuilder
  3. # 4

To @Arnd Schmidt:

Left to right stuff...
This is how the PBVM adds values to the stack.

How about C# :-) ?

Modified C#:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace ConsoleApp2
{
    class Program
    {
        static void Main(string[] args)
        {
            string ls_str = "";

            f_show_string(ls_str, f_set_string(1, ref ls_str), ls_str);
            f_show_string(ls_str, f_set_string(2, ref ls_str), ls_str);
            Console.ReadKey();
        }
        static public int f_set_string(int ai_in, ref string as_out)
        {
            if (ai_in == 1)
                as_out = "one";
            else
                as_out = "two";

            return ai_in;
        }

        static public void f_show_string(string as_string, int ai_int, string as_string_again)
        {
            Console.WriteLine("Result: " + as_string + " - " + ai_int.ToString() + " - " + as_string_again);
        }

    }
}

The result is:

Result: - 1 - one
Result: one - 2 - two

But This wouldn't be the same in C++. Here is an implementation of the first example Konstantin provided (as I'm not at all a C++ expert it may not be 100% accurate - correct):

#include <iostream>
#include <string>

int fSetString(int num1, std::string &str1) {
    if (num1 == 1)
        str1 = "one";
    else
        str1 = "two";

    return num1;
}

void fShowString(std::string str1, int num1) {
    std::cout << "Result " + str1 + " - " + std::to_string(num1) + "\n";
}

int main()
{
    std::string str1{ };

    fShowString(str1, fSetString(1, str1));
    fShowString(str1, fSetString(2, str1));
}

Here the result is:

Result one - 1
Result two - 2

The result is what I understand Konstantin was expecting in his initial example. But I believe this is due because C++ is working in a lower level...

Andreas.

Comment
  1. Roland Smith
  2. Friday, 19 April 2024 14:53 PM UTC
The & indicates 'by reference'.
  1. Helpful
  1. Andreas Mykonios
  2. Friday, 19 April 2024 15:39 PM UTC
Hi Roland. I totally agree. That's why I mentioned "The key is the & in the function declaration for the second variable". Anyway, C++ seems to do things differently... I'm not sure if the execution order of the functions is different or if this is due to C++ being able to handle things in a lower level. As I said, I'm not having any C++ experience. Just some basic C knowledge from the university. I did the test just because I found it interesting. I am reading a book and was just in the part where pointers and references were "explained". By the way, I'm not sure if the "&" should be near the variable type or the variable name (but I believe it doesn't matter).

Andreas.
  1. Helpful
  1. Arnd Schmidt
  2. Friday, 19 April 2024 21:34 PM UTC
  1. Helpful
There are no comments made yet.
  • Page :
  • 1


There are no replies made for this question yet.
However, you are not allowed to reply to this question.