how to pass by const reference?

S

Siegfried Heintze

Why does VB.NET V2 force me to pass by value for my set function? When I try
to change it to const byref it gives me a syntax error. It seems very
inefficient to be passing strings around by value when a reference to a
constant string object will do fine (all we are going to do is copy it). In
my case, would the byval for the set function cause a superfluous copy?
Thanks,
Siegfried

class person
dim m_name as string
public sub new (n as string)
m_name = n
end sub
public property name () as string
Get
return m_name
end get
set ( const byref value as string)
m_name = value
end set
end Property
public overloads overrides function ToString() as string
return m_name
end function
protected overloads overrides sub Finalize()
outp.WriteLine("~" & name )
MyBase.Finalize()
end sub
End Class
 
M

Michael C

Siegfried Heintze said:
Why does VB.NET V2 force me to pass by value for my set function? When I
try to change it to const byref it gives me a syntax error. It seems very
inefficient to be passing strings around by value when a reference to a
constant string object will do fine (all we are going to do is copy it).
In my case, would the byval for the set function cause a superfluous copy?

It doesn't create a second copy of the string, just the pointer to it. So
you have 2 pointers pointing to the 1 string. If you change the string from
1 pointer it will create a copy then I believe.

Michael
 
R

Rory Becker

Why does VB.NET V2 force me to pass by value for my set function?
set ( const byref value as string)

I have never heard of the const keyword being used here.

Try skipping it.
 
S

Scott M.

Michael C said:
It doesn't create a second copy of the string, just the pointer to it. So
you have 2 pointers pointing to the 1 string. If you change the string
from 1 pointer it will create a copy then I believe.

That is correct. By default all arguments in VB .NET are passes ByVal and
passing an argument ByVal means you get a copy - - but not necessarially a
copy of the data. If you pass a reference type (which a String is) ByVal,
you get a copy of the pointer to the reference type, thus having two ways to
access the one memory address. If you pass a value type (like an Integer)
ByValue, then you get a copy of the actual data stored on the stack.

If you were to pass a reference type (String) ByRef, then you'd get a
pointer to the original pointer, which points to the memory. A pointer to a
pointer is not as effiicient as a copy of the first pointer.
 
S

Scott M.

You can't do this.

Const is used to declare a constant and when declaring a constant, you must
assign it a value. Const can't be used to force an argument to become
constant.

-Scott
 
S

SurturZ

My understanding is that in .NET, all strings with the same contents will be
the same instance anyway.

So for example try the following code
Dim strA As String = "ABCDEF"
Dim strB As String = "ABCDEF"
MsgBox(String.ReferenceEquals(a, b))

It returns "True"!

Strings are now reference types, so whether you pass ByRef or ByVal, you are
passing (or copying) a pointer, not the contents of the string itself.

I think the reason is as old as the hills. Strings in BASIC have always been
variable length, and Microsoft has always tried to hide Pointers, memory
addresses etc from BASIC programmers. Being variable length, you need either
a terminator or a length field in memory so the computer knows where the end
of the string is. But in the BASIC paradigm, the "whole variable" only
consists of the characters, so the language must hide the terminator/length
field. The way VB does this is by making strings Reference types, then making
strings immutable and non-repeating. So if you do the comparison
If strA = strB Then ...
technically you are comparing REFERENCES (ie. that they point to the same
part of memory) rather than comparing the contents of the variables.
 
S

SurturZ

Addendum: In some ways, it is quite elegant, since comparisons will take the
same amount of time irrespective of the size of the strings being compared
(i.e. there is no character-by-character comparison). Also, additional copies
of the string take up an insignificant amount of memory.

Downside is that code like:
for i as integer = 0 to 100: strA &= "A": Next i
would be much slower, since you are creating a new string at each iteration
rather than extending an existing one. (I think there is a StringBuilder
class which is designed for this sort of work).

One major change from VB6 is that Strings are no longer collections of
Bytes, but collections of Characters. In other words, Strings are no longer a
good choice for storing binary data. Byte arrays are fairly good, but I get
sick of type CByte whenever I want to use a particular byte value as an
operand. Oh for a type character for byte!!

At least they got rid of BSTRs!!
 
S

Scott M.

SurturZ said:
My understanding is that in .NET, all strings with the same contents will
be
the same instance anyway.

So for example try the following code
Dim strA As String = "ABCDEF"
Dim strB As String = "ABCDEF"
MsgBox(String.ReferenceEquals(a, b))

It returns "True"!

This is true. Before a new string is made on the heap, the "intern pool" is
checked to see if it already is in the pool. If so, then the same string
object is used for the new variable, if not, a new string object is created
in memory. While this increases performance, it doesn't change the basic
ByVal/ByRef point.
Strings are now reference types, so whether you pass ByRef or ByVal, you
are
passing (or copying) a pointer, not the contents of the string itself.

Yes, but in one case you are making a copy of a pointer that points directly
at the object on the heap and in the other you are making a pointer that
points to the first pointer (which is slightly less efficient).
 
H

Herfried K. Wagner [MVP]

Siegfried Heintze said:
Why does VB.NET V2 force me to pass by value for my set function? When I
try to change it to const byref it gives me a syntax error. It seems very
inefficient to be passing strings around by value when a reference to a
constant string object will do fine (all we are going to do is copy it).
In my case, would the byval for the set function cause a superfluous copy?

The value is not copied, it's only a reference.

I suggest to read the chapters of the documentation dealing with the
differences between reference and value types. 'String' is a reference type
and thus passing it 'ByVal' won't create a copy of the whole string.
Instead, just a pointer is copied to prevent modification of the reference
passed to the parameter. Passing a reference type by reference (via
'ByRef') will allow the called method to modify the reference passed to it.
 
C

Cor Ligthert[MVP]

Siegried,

It is always more efficient (in a matter of processing) to pass something by
value then by reference.
By Reference means nothing more than that the By value reference is placed
in a box.

However the behaviour of a type (by instance a string is immutable) can make
that you need sometimes to pass by reference.

Cor
 
B

Bill McCarthy

Hi Cor,

Cor Ligthert said:
Siegried,

It is always more efficient (in a matter of processing) to pass something
by value then by reference.

That depends. If you have a large value type, and you want to modify one
value, then passing ByRef is usually more efficient than copying the entire
value type in then out again.

By Reference means nothing more than that the By value reference is placed
in a box.

uhm, not really. Every field and local variable has a slot, fields on the
heap, local variables on the stack. ByRef passes that location, ByVal
passes the value stored at that location.


However the behaviour of a type (by instance a string is immutable) can
make that you need sometimes to pass by reference.

If you want to replace a reference with another than you have to pass ByRef.
To me, this should be the design criteria. If you are not potentially
replacing the reference with another then avoid ByRef.

Typically I rarely use ByRef, although I have round it is sometimes
necessary with extension methods and lambdas in order to avoid doing an
assignment.
 
O

\(O\)enone

Scott said:
This is true. Before a new string is made on the heap, the "intern
pool" is checked to see if it already is in the pool. If so, then
the same string object is used for the new variable, if not, a new
string object is created in memory.

Are you entirely sure about that? As I understand it, the COMPILER does that
at compilation time, but at run-time no such thing occurs.

For example:

\\\
Dim a As String
Dim b As String

a = "ABCDEF"
b = "ABC"
b &= "DEF"

MsgBox(String.ReferenceEquals(a, b))
///

Unlike SurturZ's example, this displays False. The compiler doesn't see the
string assignment to variable "b" as being the same as to "a" at compile
time, and so the two strings exist separately in memory despite having the
exact same content.
 
B

Bill McCarthy

Now if you were to use String.Intern on b, you'd get back to a reference to
a. The intern table is used for constant strings, not dynamically created
strings. to use it for dynamically created strings, you need to do the
interning manually
 
B

Bill McCarthy

Oh, and I forgot to mention, technically the interning of constant strings
is not done by the compiler, rather it is done by the JIT/runtime. You can
turn off string interning of constants by ngen'ing the assembly when you
have a no interning attribute in the assembly.
<Assembly:
CompilationRelaxationsAttribute(CompilationRelaxations.NoStringInterning)>

So yes it is the compiler, but the JIT or ngen compiler not the vbc or csc
compilation ;)



Bill McCarthy said:
Now if you were to use String.Intern on b, you'd get back to a reference
to a. The intern table is used for constant strings, not dynamically
created strings. to use it for dynamically created strings, you need to do
the interning manually
 
J

J.B. Moreno

SurturZ said:
So if you do the comparison
If strA = strB Then ...
technically you are comparing REFERENCES (ie. that they point to the same
part of memory) rather than comparing the contents of the variables.

This is incorrect.

Microsoft.VisualBasic.CompilerServices.StringType.StrCmp is used for
the = < and > operators.
 
S

Scott M.

J.B. Moreno said:
This is incorrect.

Microsoft.VisualBasic.CompilerServices.StringType.StrCmp is used for
the = < and > operators.

That's true. If you wan to compare the two variables to see if they point
to the same object in memor, use the "Is" operator.
 
J

J.B. Moreno

Scott M. said:
That's true. If you wan to compare the two variables to see if they point
to the same object in memor, use the "Is" operator.


While that's true, it's less important than the fact that you can have
more than one instance of a string with the same value.


IF "1234".SubString(1,2) IS "1234".SubString(1,2) THEN
' never going to happen
END IF

SurturZ was confused by the fact that there will only be one instance
of a string CONSTANT in a namespace.

So that if you say

Dim str1 as String = "1234"
Dim str2 as String = "1234"

IF str1 IS str2 THEN
'this happens
END IF


But that's because what's really happening under the hood is:

DIM cStr1234 AS String = "1234"

Dim str1 as String = cStr1234
Dim str2 as String = cStr1234

IF str1 IS str2 THEN
'this happens
END IF

On a somewhat related note, if you use Option Compare Text and then
compare "a" to "A" the answer could be true for you and false for
someone else, without a single change in the program.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top