HasElementType

  • Thread starter Thread starter William Stacey
  • Start date Start date
W

William Stacey

Type.HasElementType -
"Gets a value indicating whether the current Type encompasses or refers to
another type; that is, whether the current Type is an array, a pointer, or
is passed by reference." So why does this return false? String is passed
by ref and is a ref type.

string s = "text";
Console.WriteLine("String hasElement:" + s.GetType().HasElementType);

Output:
String hasElement:False
 
William,

In the documentation for the HasElementType property, the meaning of
"reference" is not a manged reference, but rather, a reference in the
classic C++ sense (it refers to getting the type of "Int32&" for a reference
type). If you try your code with the type of Object, it returns false as
well.

Hope this helps.
 
"true if the Type is an array, a pointer, or is passed by reference;
otherwise, false."
So below, byte[] is passed by ref, as is int[] and they return true as
expected. Pointer is true as expected. However string is also a ref type
and passed by ref as is object, so why are they false?

public static void Main()
{
unsafe {
Console.WriteLine("byte[].HasElementType:
"+typeof(byte[]).HasElementType);
Console.WriteLine("int[].HasElementType: "+typeof(int[]).HasElementType);
Console.WriteLine("byte*.HasElementType: "+typeof(byte*).HasElementType);
Console.WriteLine("string.HasElementType:
"+typeof(string).HasElementType);
Console.WriteLine("object.HasElementType:
"+typeof(object).HasElementType);
}
}

Output:
byte[].HasElementType: True
int[].HasElementType: True
byte*.HasElementType: True
string.HasElementType: False
object.HasElementType: False

--
William Stacey, MVP

Nicholas Paldino said:
William,

In the documentation for the HasElementType property, the meaning of
"reference" is not a manged reference, but rather, a reference in the
classic C++ sense (it refers to getting the type of "Int32&" for a reference
type). If you try your code with the type of Object, it returns false as
well.

Hope this helps.


--
- Nicholas Paldino [.NET/C# MVP]
- (e-mail address removed)

William Stacey said:
Type.HasElementType -
"Gets a value indicating whether the current Type encompasses or refers to
another type; that is, whether the current Type is an array, a pointer, or
is passed by reference." So why does this return false? String is passed
by ref and is a ref type.

string s = "text";
Console.WriteLine("String hasElement:" + s.GetType().HasElementType);

Output:
String hasElement:False
 
William Stacey said:
"true if the Type is an array, a pointer, or is passed by reference;
otherwise, false."
So below, byte[] is passed by ref, as is int[] and they return true as
expected.

No, byte[] references are passed by value, but they fall into the "if
the Type is an array" clause of the documentation.
Pointer is true as expected. However string is also a ref type
and passed by ref as is object, so why are they false?

They're *not* passed by reference.

See http://www.pobox.com/~skeet/csharp/parameters.html
 
No, byte[] references are passed by value, but they fall into the "if
the Type is an array" clause of the documentation.

The "pointer" to the array is passed by value. However it is still a
reference type. If you use the "ref" keyword to pass it, then your passing
a pointer to a pointer. And the pointer is passed by value. The
distinction is, value types are passed by value on the stack, ref types pass
the 4 bytes pointer by default. It still passing by reference (not to
confuse that with the "ref" keyword).
They're *not* passed by reference.

See above.
 
William Stacey said:
No, byte[] references are passed by value, but they fall into the "if
the Type is an array" clause of the documentation.

The "pointer" to the array is passed by value. However it is still a
reference type. If you use the "ref" keyword to pass it, then your passing
a pointer to a pointer. And the pointer is passed by value.

No, if you're using the "ref" keyword, you're passing a variable by
reference. Although that would usually be achieved by passing a pointer
to the variable, I don't believe it *has* to be. (The CLR specification
probably makes sure that it does, in fact, but more generally, when an
l-value is passed by reference it is *usually* implemented by using a
pointer, but that's an implementation issue.)
The distinction is, value types are passed by value on the stack, ref types pass
the 4 bytes pointer by default.

But that reference is the value of the expression to start with.
It still passing by reference (not to confuse that with the "ref" keyword).

No, it's really *not* passing by reference. Passing a pointer is *not*
the same as passing by reference. C, for example, doesn't have pass-by-
reference semantics even though you can pass pointers. (K&R, 2nd
edition, says that absolutely specifically, btw.)

If you can find any *formal* definition of pass-by-reference semantics
which would fit with the idea that C# "passes arrays by reference" I'll
be very surprised. (I've offered this challenge to many people before
in various forms, and not a single one has found any such definition.)

By formal definitions, the idea of passing an object by reference
doesn't make any sense in the first place - you can only pass an
l-value by reference, and an object itself isn't an l-value.

Claiming that C# passes object by reference by default (arrays, in this
case) can be very confusing to people who really *do* know what pass-
by-reference means, and for others it makes life more complicated than
it needs to be. (When you understand that the value of an expression is
*never* an object itself, all kinds of things become really easy to
understand.)
See above.

Did you read the article I gave the link to?
 
Thanks Jon, instead of commenting on all that, here is a document I created
that gets into the detail of this at the memory level. This shows exactly
what gets passed when passing a byte[] by-value and by-reference. There is
also a few other bits that you may find interesting or could answer
(question is noted in the text.) Please feel free to comment. If you can't
view this, please also let me know. Cheers!
http://www.mvptools.com/docs/PassByteArrays.mht
 
William Stacey said:
Thanks Jon, instead of commenting on all that, here is a document I created
that gets into the detail of this at the memory level. This shows exactly
what gets passed when passing a byte[] by-value and by-reference. There is
also a few other bits that you may find interesting or could answer
(question is noted in the text.) Please feel free to comment. If you can't
view this, please also let me know. Cheers!
http://www.mvptools.com/docs/PassByteArrays.mht

The problem with looking at it at the implementation level is that
pass-by-reference and pass-by-value aren't *defined* at the
implementation level. They're defined in terms of parameters. When you
talk about the "pointers [to the variables themselves] being passed by
value" in paragraph 3, that doesn't apply to any definition of pass-by-
value I've seen, because the pointers aren't the value of any of the
parameters. The point of describing pass-by-reference and pass-by-value
semantics is to understand how *parameters* are passed.

In the case of pass-by-value, the value of the actual parameter
expression becomes the value of the new local variable (the formal
parameter).

In the case of pass-by-reference, the formal parameter is aliased with
the actual parameter expression (which must therefore be an L-value) so
that any changes in the formal parameter's value are also visible as
changes to the actual parameter expression's value.

The parameters in the call

GetRefs (ba, ba2, ref ba, ref ba2)

are ba, ba2, ba (again), and ba2 (again). The first parameters are
passed by value, the second are passed by reference. There are no other
parameters, so no other things can really be described as being passed,
IMO. The title of your page is misleading in this respect - byte arrays
themselves can never be passed, as there is no expression whose value
is a byte array - only a *reference* to a byte array.

One of the reasons the explanation gets difficult (paragraph 6) is that
the JIT gets involved - and frankly, I don't understand the details of
what the JIT does. That's the good thing about sticking at the language
level - everything can be explained by the language specification.
Obviously we need to have some ideas about performance etc, but in
terms of explaining the way the language behaves, we can stick at the
language specification level.
 
value" in paragraph 3, that doesn't apply to any definition of pass-by-
value I've seen, because the pointers aren't the value of any of the
parameters.

The pointers are the only values that get passed in both cases regarding
reference types. In the (ba, ref ba) example: the first parameter that is
passed is the reference (i.e. pointer) that ba holds. In the second
parameter it is the pointer to ba that gets passed (or reference to ba.) In
both cases, references are passed. That was my point and I think we both
agree.
In the case of pass-by-value, the value of the actual parameter
expression becomes the value of the new local variable (the formal
parameter).

Agreed. I don't think I said otherwise. However there is that exception
where a new local variable address is not created as I showed. I still
wouldn't mind getting some discussion on that from some kind sole.
In the case of pass-by-reference, the formal parameter is aliased with
the actual parameter expression (which must therefore be an L-value) so
that any changes in the formal parameter's value are also visible as
changes to the actual parameter expression's value.

Agreed. I think I showed that in some detail.
IMO. The title of your page is misleading in this respect - byte arrays
themselves can never be passed, as there is no expression whose value
is a byte array - only a *reference* to a byte array.

You are welcome to your opinion. As a byte[] is a reference type, it does
make sense, IMO, to talk about passing reference types by value and by
reference. In fact, there is a help page on it. There is also one titled
"Passing Arrays Using ref and out". I think you are parsing a bit fine here
for some reason. I never said, indirectly or otherwise, that you actually
pass the bytes of the array itself. If nothing else, that is very clear in
the text.
Obviously we need to have some ideas about performance etc, but in
terms of explaining the way the language behaves, we can stick at the
language specification level.

Sure that is fine for many things. Sometimes you need more. It all depends
on what your talking about or what the question is. Cheers.
 
William Stacey said:
The pointers are the only values that get passed in both cases regarding
reference types. In the (ba, ref ba) example: the first parameter that is
passed is the reference (i.e. pointer) that ba holds. In the second
parameter it is the pointer to ba that gets passed (or reference to ba.) In
both cases, references are passed. That was my point and I think we both
agree.

Sort of - but not quite. The word "reference" here is problematic here
because it's so overloaded. In strict ways no reference gets passed in
the second case - the *parameter* gets passed *by* reference, and it
being a reference-type variable doesn't actually make any conceptual
difference. What I'm trying to get at is that the value itself is
entirely disregarded (and not even evaluated). Now the fact that it's
probably *implemented* as a a pointer which is like a reference
shouldn't (IMO) come into these discussions, as that's an
implementation detail which should be clearly separated from the
language terminology.
Agreed. I don't think I said otherwise.

No, I was just clarifying.
However there is that exception
where a new local variable address is not created as I showed. I still
wouldn't mind getting some discussion on that from some kind sole.

But *conceptually* it still *is* being created. I don't care what the
implementation actually does so long as the end result is the same as
the spec says it will be.
Agreed. I think I showed that in some detail.

Again, just clarifying.
IMO. The title of your page is misleading in this respect - byte arrays
themselves can never be passed, as there is no expression whose value
is a byte array - only a *reference* to a byte array.

You are welcome to your opinion. As a byte[] is a reference type, it does
make sense, IMO, to talk about passing reference types by value and by
reference.

It absolutely makes sense to talk about passing reference types by
value and by reference - but passing a byte array reference normally,
it is passed by value, rather than the array being passed by reference
as you originally claimed.
In fact, there is a help page on it. There is also one titled
"Passing Arrays Using ref and out". I think you are parsing a bit fine here
for some reason. I never said, indirectly or otherwise, that you actually
pass the bytes of the array itself.

No, but you said that byte arrays were passed by reference (implying
"by default"), when in fact byte array references are passed by value,
which is a different set of semantics.
If nothing else, that is very clear in the text.


Sure that is fine for many things. Sometimes you need more. It all depends
on what your talking about or what the question is. Cheers.

But the question, as I understand it, is "are byte arrays passed by
reference by default" as that was the thing I disagreed with in your
post much earlier on. Determining the answer to that question doesn't
require anything beyond the language specification and a definition of
what "pass by reference" and "pass by value" each mean.
 
Back
Top