You can't pass an expression as a parameter that is defined as ByRef??? Really?

Ran into this gem of a compiler error today:

“You can’t pass an expression as a parameter that is defined as ByRef”

Here is the code that generated the ire of the compiler gods:

findMatchingWaveformPresetIfExists(channelWaveformProperties(i))

Obviously, to fix this is simple:

dim wp as waveformProperties = channelWaveformProperties(i)
findMatchingWaveformPresetIfExists(wp)

But this brings up a pretty basic question… Why can’t I do this in the first place? I would expect that at runtime the inner expression would be evaluated (i.e., dereference the item from the array) first, and then passed to the method. Can the existing compiler really not tell that the array (or indeed, a function call etc) will return the correct type to match the ByRef definition?

Will the fabled new compiler slated for sometime before the end of the world allow for things like this?

If you think about it, the error message makes perfect sense. When you pass something ByRef, you are passing a pointer (address) to the value or object. How can the compiler know the value of an expression and where that value may ultimately be stored in memory at compile time in order to pass its address?

What is waveformProperties ? Maybe you just don’t need the byref to be using a reference to the type.

Is channelWaveformProperties an array or a function?

Randy, your comment beautifully illustrated why the compiler should not even have to care - a pointer is a pointer is a pointer. If I tell the compiler that I’ll be passing a pointer to an object to a method, why should it care where I get that pointer at runtime?

It can’t. It also can’t tell where in memory ANYTHING will be at compile time.

@Rick Araujo - waveformProperties is a class that handles managing electrical waveforms for a device we’re developing. It stores things such as frequency, polarity, amplitude, etc. It includes several methods for doing various things. The hardware we are working on supports up to 5 simultaneous waveforms, so I have an array of 5 waveformProperties called channelWaveformProperties. Apparently the compiler won’t let me say: take the ith waveformProperty from the channelWaveformProperties array as your argument. Instead, I have to pull the ith waveformProperty out myself into a locally dim’d variable, then pass that instead.

I hate to bring up other languages etc, but I can’t think of any other language I’ve used that is incapable of evaluating an expression prior to passing the results to a method in this manner. This includes Java, C (++), PHP, Ruby, Objective-C, etc.

Reminds me of when I first started using Xojo (ahem, RealBasic 4) back in the day. Back then, you could not pass an array to a method at all… as in, you could not declare a method that took an array as an argument. The compiler simply would not do it at all.

So you don’t need a ByRef. Objects are automatically passed as reference. :wink:

@Rick Araujo - this is why I have always felt it was odd that an array and a function call use the same syntax - i.e., parentheses. When reading code, it is sometimes hard to tell if it is an array or a method. When showing people Xojo code for the first time, this is one of the oddities that I always have to explain…“yeah, they decided to use parens for arrays instead of the [ and ] brackets like every mainstream language in the world does. Don’t ask why. Xojo just does some weird stuff.”

ByRef says you plan on replacing the pointer itself, not just modifying what it points to. That’s why the location has to be predictable. ByRef says you could have a completely different object when the function returns, not just a modified object. Do you really need to pass the parameter ByRef?

Yep, I know. But it’s due to a language legacy. Maybe, someday, they will decided to do a huge overhaul to the language (as Python did in v3) changing all the oddities to a better language design (in my opinion) making it even incompatible with the old language and breaking old code in a purpose. Maybe they include a project setting like “Compile as Xojo V1 Syntax” for retro compatibility of old projects.

[code]Sub myproc1( o As waveformProperties)
// o.prop1 = 11
// o.prop2 = 22
End

Dim myprop As New waveformProperties
myProc1(myprop) // Should work, myprop is already passed ByRef[/code]

Same for an Array of waveformproperties

Thanks @Rick Araujo - that does work fine, not sure why I convinced myself to try to pass ByRef instead… had my head in other environments that do things differently lately, I suppose.

Passing by reference and passing by value in Xojo appear to behave a little differently than I’m used to in other languages. To make sure I have things straight, in Xojo:

If it’s an instantiated object or an array of any type, it is ALWAYS passed ByRef, even if you try to define the method you are calling to receive things ByVal.

If it’s an intrinsic type (Integer, Double, String, Structure, Currency (or anything defined as a “Data Type” in the language reference, it is passed ByVal unless you specify ByRef.

Which begs the question: Why in the world does ByVal even exist?

Maybe you get a compiler error when you NEED to guarantee that you passed a copy and not a reference by mistake.

But I also think my original question has been lost: Let’s assume that I had the following method:

Sub doSomething(ByRef i as Integer) i = Pow(i + 1, 2) //silly example. End Sub

and then this chunk of code:

[code] dim numbers() as Integer
numbers.append(1)
numbers.append(2)
numbers.append(3)

doSomething(numbers(1))[/code]

The compiler barks at me because it can’t seem to figure out that it just needs to pull an item out of the numbers array and pass it’s address to doSomething. I’m forced to do it manually:

dim numbers() as Integer numbers.append(1) numbers.append(2) numbers.append(3) dim i as integer = numbers(1) doSomething(i) numbers(1) = i

This just strikes me as odd compiler behavior. The compiler should know that numbers() is going to be an array of Integers, and that Integers can be passed byRef, ergo an item in numbers() should be allowed to be passed in this manner.

Just another oddity in Xojo, I suppose.

Michael, pardon me, but you are wrong about Arrays and Objects. They are ByRef in any case. Check here http://documentation.xojo.com/index.php/ByRef

@Michael Hußmann - both the ByRef and the ByVal docs include this Note:

He is not passing an expression, he is passing an object. And as stated, it will be by reference in any case. :wink:

When you declare a variable of an object type, that variable contains a reference to the object, not the object itself. When you pass that variable to a function (without using ByRef), you are passing the reference (a pointer really) ByVal. That means you cannot change the value of the reference - it will still point to the same object when the function returns, no matter what you do in the function. If you pass it ByRef, though, the function may actually change the object instance that the variable refers to. So it does make sense to think about passing an object ByVal or ByRef. There is still a distinction.

sub foo(ref as Class1)
   ref = new Class1  // creates object B
end

dim p as new Class1    // creates object A
foo(p)
// p still refers to object A
sub foo(ByRef ref as Class1)
  ref = new Class1  // creates object B
end

dim p as new Class1   // creates object A
foo(p)
// p now refers to object B

I should test it before emitting an opinion, but assuming you are right, one work around could be:

Sub doSomething(ByRef a() As Integer, i as Integer)
a(i) = Pow(a(i) + 1, 2) //silly example.
End Sub

and then this chunk of code:

dim numbers() as Integer
numbers.append(1)
numbers.append(2)
numbers.append(3)

doSomething(numbers, 1)