Re: pass a struct by value/ref and size of the struct

2016-03-21 Thread tsbockman via Digitalmars-d-learn

On Monday, 21 March 2016 at 23:31:06 UTC, ref2401 wrote:
I have got a plenty of structs in my project. Their size varies 
from 12 bytes to 128 bytes.
Is there a rule of thumb that states which structs I pass by 
value and which I should pass by reference due to their size?


Thanks.


Not really. It depends on the platform - most especially on the 
details of the cache hierarchy, I think.


The best answer to this kind of thing is generally: Do some 
benchmarks. (Although, you'll have to be somewhat skilled at 
benchmarking to get useful results, since the
 performance difference in most code is probably not that large 
either way.)


Note, also, that functions which are doing so little work with 
their arguments that you can actually notice the speed difference 
of pass-by-ref versus pass-by-value for small data structures are 
likely to be inlined anyway - in which case it makes no 
difference which you chose (I think...).


If you really just want a number, though - maybe try 
pass-by-reference for anything larger than 32 bytes.


way to warn about __traits(compiles , ...) that fail due to compile time interpretation lacking body ?

2016-03-21 Thread Nicholas Wilson via Digitalmars-d-learn
So I was recently trying to optimise a string substitution 
function by reserving capacity. however this was being used at 
compile time (mixin) and the body of arr.reserve(n) was not 
available causing a bug that was easy to observe but very 
difficult to determine why. As a result code was taking a wrong 
static if branch. I know __traits(compiles, ... ) is a blunt tool 
but it feels very wrong to have a function that works and 
complies at runtime, fail to compile at compile time and not 
receive any warning.







Re: size_t index=-1;

2016-03-21 Thread tsbockman via Digitalmars-d-learn
On Tuesday, 22 March 2016 at 00:18:54 UTC, Steven Schveighoffer 
wrote:

On 3/21/16 7:43 PM, tsbockman wrote:
The false positive rate would certainly be *much* lower than 
your
outlandish 10,000 : 1 estimate, given a good compiler 
implementation.


I wouldn't say it's outlandish given my understanding of the 
problem. The question is, does the pain justify the update? I 
haven't run it against my code or any code really, but I can 
see how someone is very good at making correct uses of the 
implicit conversion.


Well that's the real problem here then, isn't it?

I wouldn't want this stuff "fixed" either, if I thought false 
positives would outnumber useful warnings by 10,000 : 1.


However, I already *know* that's not the case, from my own tests. 
But at this point I'm obviously not going to convince you, except 
by compiling some concrete statistics on what got flagged in some 
real code bases.


And this I plan to do (in some form or other), once `checkedint` 
and/or the fix for DMD issue 259 are really ready. People can 
make an informed decision about the trade-offs then.


Re: size_t index=-1;

2016-03-21 Thread Steven Schveighoffer via Digitalmars-d-learn

On 3/21/16 7:43 PM, tsbockman wrote:

On Monday, 21 March 2016 at 22:29:46 UTC, Steven Schveighoffer wrote:

It depends on the situation. foo may know that x is going to be short
enough to fit in an int.

The question becomes, if 99% of cases the user knows that he was
converting to a signed value intentionally, and in the remaining 1% of
cases, 99% of those were harmless "errors", then this is going to be
just a nuisance update, and it will fail to be accepted.


My experimentation strongly suggests that your "99.99% false positive"
figure is way, *way* off. This stuff is both:


Maybe, what would be a threshold that people would find acceptable?


1) Harder for people to get right than you think (you can't develop good
intuition about the extent of the problem, unless you spend some time
thoroughly auditing existing code bases specifically looking for this
kind of problem), and also


It matters not to the person who is very aware of the issue and doesn't 
write buggy code. His code "breaks" too.


I would estimate that *most* uses of if(arr) in the wild were/are 
incorrect. However, in one particular user's code *0* were incorrect, 
even though he used it extensively. This kind of problem is what lead to 
the change being reverted. I suspect this change would be far more 
likely to create more headaches than help.



2) Easier for the compiler to figure out than you think - I was really
surprised at how short the list of problems flagged by the compiler was,
when I tested Lionello Lunesu's work on the current D codebase.


This is highly subjective to whose code you use it on.


The false positive rate would certainly be *much* lower than your
outlandish 10,000 : 1 estimate, given a good compiler implementation.


I wouldn't say it's outlandish given my understanding of the problem. 
The question is, does the pain justify the update? I haven't run it 
against my code or any code really, but I can see how someone is very 
good at making correct uses of the implicit conversion.



With respect to your specific example:

1) The memory limit on a true 32-bit system is 4GiB, not 2GiB. Even with
an OS that reserves some of the address space, as much as 3GiB or 3.5GiB
may be exposed to a user-space process in practice.


Then make it long len = x.length on a 64-bit system.

Only reason I said assume it's 32-bit, is because on 64-bit CPU, using
int is already an error. The architecture wasn't important for the
example.


Huh? The point of mine which you quoted applies specifically to 32-bit
systems. 32-bit array lengths can be greater than `int.max`.

Did you mean to reply to point #3, instead?


You seem to spend a lot of time focusing on 32-bit architecture, which 
was not my point at all.


My point is that most arrays and uses are short enough to be handled 
with a signed value as the length.


If this is a generic library function, sure, we should handle all 
possibilities. This doesn't mean someone's command line utility 
processing strings from the argument list should have to worry about 
that (as an example). Breaking perfectly good code is something we 
should strive against.


-Steve


Re: size_t index=-1;

2016-03-21 Thread tsbockman via Digitalmars-d-learn
On Monday, 21 March 2016 at 22:29:46 UTC, Steven Schveighoffer 
wrote:
It depends on the situation. foo may know that x is going to be 
short enough to fit in an int.


The question becomes, if 99% of cases the user knows that he 
was converting to a signed value intentionally, and in the 
remaining 1% of cases, 99% of those were harmless "errors", 
then this is going to be just a nuisance update, and it will 
fail to be accepted.


My experimentation strongly suggests that your "99.99% false 
positive" figure is way, *way* off. This stuff is both:


1) Harder for people to get right than you think (you can't 
develop good intuition about the extent of the problem, unless 
you spend some time thoroughly auditing existing code bases 
specifically looking for this kind of problem), and also


2) Easier for the compiler to figure out than you think - I was 
really surprised at how short the list of problems flagged by the 
compiler was, when I tested Lionello Lunesu's work on the current 
D codebase.


The false positive rate would certainly be *much* lower than your 
outlandish 10,000 : 1 estimate, given a good compiler 
implementation.



With respect to your specific example:

1) The memory limit on a true 32-bit system is 4GiB, not 2GiB. 
Even with
an OS that reserves some of the address space, as much as 3GiB 
or 3.5GiB

may be exposed to a user-space process in practice.


Then make it long len = x.length on a 64-bit system.

Only reason I said assume it's 32-bit, is because on 64-bit 
CPU, using int is already an error. The architecture wasn't 
important for the example.


Huh? The point of mine which you quoted applies specifically to 
32-bit systems. 32-bit array lengths can be greater than 
`int.max`.


Did you mean to reply to point #3, instead?


pass a struct by value/ref and size of the struct

2016-03-21 Thread ref2401 via Digitalmars-d-learn
I have got a plenty of structs in my project. Their size varies 
from 12 bytes to 128 bytes.
Is there a rule of thumb that states which structs I pass by 
value and which I should pass by reference due to their size?


Thanks.


Re: size_t index=-1;

2016-03-21 Thread Steven Schveighoffer via Digitalmars-d-learn

On 3/21/16 4:27 PM, tsbockman wrote:

On Monday, 21 March 2016 at 17:38:35 UTC, Steven Schveighoffer wrote:

Your definition of when "implicit casting is really a bad idea" is
almost certainly going to include cases where it really isn't a bad idea.


This logic can be applied to pretty much any warning condition or
safety/correctness-related compiler feature; if it were followed
consistently the compiler would just always trust the programmer, like
an ancient C or C++ compiler with warnings turned off.


Right, if we were starting over, I'd say let's make sure you can't make 
these kinds of mistakes. We are not starting over though, and existing 
code will have intentional uses of the existing behavior that are NOT 
bugs. Even that may have been rejected by Walter since a goal is making 
C code easy to port.


Note that we already have experience with such a thing: if(arr). Fixing 
is easy, just put if(arr.ptr). It was rejected because major users of 
this "feature" did not see any useful improvements -- all their usages 
were sound.



The compiler isn't all-knowing, and there will always be cases where
the user knows best (and did the conversion intentionally).


That's what explicit casts are for.


Existing code doesn't need to cast. People are lazy. I only would insert 
a cast if I needed to. Most valid code just works fine without casts, so 
you are going to flag lots of valid code as a nuisance.



An obvious one is:

void foo(ubyte[] x)
{
  int len = x.length;
}

(let's assume 32-bit CPU) I'm assuming the compiler would complain
about this, since technically, len could be negative! Disallowing such
code or requiring a cast is probably too much.


But that *is* a bad idea - there have been real-world bugs caused by
doing stuff like that without checking.


It depends on the situation. foo may know that x is going to be short 
enough to fit in an int.


The question becomes, if 99% of cases the user knows that he was 
converting to a signed value intentionally, and in the remaining 1% of 
cases, 99% of those were harmless "errors", then this is going to be 
just a nuisance update, and it will fail to be accepted.



With respect to your specific example:

1) The memory limit on a true 32-bit system is 4GiB, not 2GiB. Even with
an OS that reserves some of the address space, as much as 3GiB or 3.5GiB
may be exposed to a user-space process in practice.


Then make it long len = x.length on a 64-bit system.

Only reason I said assume it's 32-bit, is because on 64-bit CPU, using 
int is already an error. The architecture wasn't important for the example.


-Steve


Re: Something wrong with GC

2016-03-21 Thread tsbockman via Digitalmars-d-learn

On Sunday, 20 March 2016 at 07:49:17 UTC, stunaep wrote:
The gc throws invalid memory errors if I use Arrays from 
std.container.

...
Not sure what to do here


I don't know what your larger goal is, but maybe 
std.array.Appender would be a better fit?


Re: size_t index=-1;

2016-03-21 Thread tsbockman via Digitalmars-d-learn
On Monday, 21 March 2016 at 17:38:35 UTC, Steven Schveighoffer 
wrote:
Your definition of when "implicit casting is really a bad idea" 
is almost certainly going to include cases where it really 
isn't a bad idea.


This logic can be applied to pretty much any warning condition or 
safety/correctness-related compiler feature; if it were followed 
consistently the compiler would just always trust the programmer, 
like an ancient C or C++ compiler with warnings turned off.


The compiler isn't all-knowing, and there will always be cases 
where the user knows best (and did the conversion 
intentionally).


That's what explicit casts are for.


An obvious one is:

void foo(ubyte[] x)
{
  int len = x.length;
}

(let's assume 32-bit CPU) I'm assuming the compiler would 
complain about this, since technically, len could be negative! 
Disallowing such code or requiring a cast is probably too much.


But that *is* a bad idea - there have been real-world bugs caused 
by doing stuff like that without checking.


With respect to your specific example:

1) The memory limit on a true 32-bit system is 4GiB, not 2GiB. 
Even with an OS that reserves some of the address space, as much 
as 3GiB or 3.5GiB may be exposed to a user-space process in 
practice.


2) Many 32-bit CPUs have Physical Address Extension, which allows 
them to support way more than 4GiB. Even a non-PAE-aware process 
will probably still be offered at least 3GiB on such a system.


3) Just because your program is 32-bit, does *not* mean that it 
will only ever run on 32-bit CPUs. On a 64-bit system, a single 
32-bit process could easily have access to ~3GiB of memory.


4) Even on an embedded system (which D doesn't really support 
right now, anyway) with a true, 2GiB memory limit, you still have 
the problem that such highly platform-dependent code is difficult 
to find and update when the time comes to port the code to more 
powerful hardware.


These kinds of things are why D has fixed-size integer types: to 
encourage writing portable code, without too many invisible 
assumptions about the precise details of the execution 
environment.


Re: Using ffmpeg in command line with D

2016-03-21 Thread Adam D. Ruppe via Digitalmars-d-learn

On Monday, 21 March 2016 at 17:26:09 UTC, Karabuta wrote:
I am new to this kind of multimedia stuff and all this is 
currently theoretical. Will this work and is it the right 
approach used by video convertor front-ends?


Eh, it is how I  did it before, it works and is pretty easy to do.


Re: No property error message

2016-03-21 Thread Steven Schveighoffer via Digitalmars-d-learn

On 3/19/16 2:36 PM, ric maicle wrote:

I got an error message with the following code saying:

   Error: no property 'length' for type 'int[string]'

Shouldn't the error message say 'length()'?


No, it should say length is a property, not a function. a.length should 
work.


Note the error message here:

struct S
{
int x;
}
void main()
{
S s;
s.x();
}

function expected before (), not s.x of type int

Please file a bug report.

-Steve


Re: size_t index=-1;

2016-03-21 Thread Steven Schveighoffer via Digitalmars-d-learn

On 3/18/16 7:48 PM, tsbockman wrote:

On Friday, 18 March 2016 at 14:51:34 UTC, Steven Schveighoffer wrote:

Note, I have made these mistakes myself, and I understand what you are
asking for and why you are asking for it. But these are bugs. The user
is telling the compiler to do one thing, and expecting it to do
something else. It's not difficult to fix, and in fact, many lines of
code are written specifically to take advantage of these rules. This
is why we cannot remove them. The benefit is not worth the cost.


Actually, I think I confused things for you by mentioning to `cast(ulong)`.

I'm not asking for a Java-style "no unsigned" system (I hate that; it's
one of my biggest annoyances with Java). Rather, I'm picking on
*implicit* conversions between signed and unsigned.


No, I understood you meant implicit casting.



I'm basically saying, "because information is lost when casting between
signed and unsigned, all such casts should be explicit". This could make
code rather verbose - except that from my experiments, with decent VRP
the compiler can actually be surprisingly smart about warning only in
those cases where implicit casting is really a bad idea.


Your definition of when "implicit casting is really a bad idea" is 
almost certainly going to include cases where it really isn't a bad 
idea. The compiler isn't all-knowing, and there will always be cases 
where the user knows best (and did the conversion intentionally).


An obvious one is:

void foo(ubyte[] x)
{
  int len = x.length;
}

(let's assume 32-bit CPU) I'm assuming the compiler would complain about 
this, since technically, len could be negative! Disallowing such code or 
requiring a cast is probably too much.


-Steve


Using ffmpeg in command line with D

2016-03-21 Thread Karabuta via Digitalmars-d-learn

Hi all,
I'm trying to convert an array of video filenames to another 
format using spawnProcess() from std.process. I want to convert 
all files in sequence with the command "ffmpeg -i filename.mp4 -o 
outputfile.webm" where process will be run one process after the 
other.


I am new to this kind of multimedia stuff and all this is 
currently theoretical. Will this work and is it the right 
approach used by video convertor front-ends?


Re: Enabling Only Top-Level Unittests

2016-03-21 Thread Adam D. Ruppe via Digitalmars-d-learn

On Monday, 21 March 2016 at 15:15:41 UTC, Nordlöw wrote:
This is because my project has grown beyond 30klines of code 
and at that scale not even D's speed is enough for getting fast 
incremental builds through dmd.


Note that lines of code isn't really important to build time...

$ time dmd -c -o- dom.d cgi.d web.d sha.d libssh2.d 
simpledisplay.d color.d minigui.d terminal.d characterencodings.d


real0m1.063s
user0m0.986s
sys 0m0.075s

$ wc dom.d cgi.d web.d sha.d libssh2.d simpledisplay.d color.d 
minigui.d terminal.d characterencodings.d

  6645  22789 173999 dom.d
  3994  16063 123572 cgi.d
  4921  18287 143876 web.d
   412   1407  10066 sha.d
   189478   5357 libssh2.d
  8850  34060 274340 simpledisplay.d
  1163   4413  27268 color.d
  2785   8150  70996 minigui.d
  3834  13888 114827 terminal.d
   473   2819  18391 characterencodings.d
 33266 122354 962692 total




Yes, compiling 33,000 lines from my libs happened in about one 
second.



My experience with slow D builds tends to be that it is caused by 
CTFE, not by scale.


Re: Enabling Only Top-Level Unittests

2016-03-21 Thread Nordlöw via Digitalmars-d-learn

On Monday, 21 March 2016 at 15:15:41 UTC, Nordlöw wrote:

I don't see any other solution for really large projects.


Except implementing memoized execution of unittests into dmd. 
Which I have discussed previously :)


Re: Enabling Only Top-Level Unittests

2016-03-21 Thread Nordlöw via Digitalmars-d-learn

On Monday, 21 March 2016 at 15:11:31 UTC, Nordlöw wrote:

On Monday, 21 March 2016 at 11:36:10 UTC, wobbles wrote:

This is quite annoying I feel.

There probably should be an option for the -unittest flag to 
only compile unittests for the source files I'm passing in, 
and not any of the tests in the -I import paths.


I very much agree.


This is because my project has grown beyond 30klines of code and 
at that scale not even D's speed is enough for getting fast 
incremental builds through dmd.


Therefore I've split my project into separate build using scons. 
With good dependency design I've reduced the build time from 
around 12 (via one single call to dmd) to 2 seconds.


I don't see any other solution for really large projects.


Re: Enabling Only Top-Level Unittests

2016-03-21 Thread Nordlöw via Digitalmars-d-learn

On Monday, 21 March 2016 at 11:36:10 UTC, wobbles wrote:

This is quite annoying I feel.

There probably should be an option for the -unittest flag to 
only compile unittests for the source files I'm passing in, and 
not any of the tests in the -I import paths.


I very much agree.


Re: Can't Compile Global Semaphores?

2016-03-21 Thread denizzzka via Digitalmars-d-learn

On Monday, 27 July 2015 at 20:12:10 UTC, John Colvin wrote:


Yes, but then core.sync.semaphore doesn't support being shared, 
so...


I don't really understand how 
https://github.com/D-Programming-Language/druntime/blob/master/src/core/sync/semaphore.d#L356 is managing to avoid this


Since that time is something cleared up? Faced with the same 
problem


Re: Enabling Only Top-Level Unittests

2016-03-21 Thread wobbles via Digitalmars-d-learn

On Monday, 21 March 2016 at 10:37:31 UTC, ZombineDev wrote:

On Monday, 21 March 2016 at 10:29:36 UTC, Nordlöw wrote:
I want to enable unittests only at the top-level of a module 
compilation.


If I have a module

top.d

that imports

dep1.d
dep2.d
...

which all contain unittests, how do I compile top.d with only 
the unittests for top.d enabled?


I think the easiest solution is to use 
http://dlang.org/spec/traits.html#getUnitTests and to run the 
tests you want manually.


This is quite annoying I feel.

There probably should be an option for the -unittest flag to only 
compile unittests for the source files I'm passing in, and not 
any of the tests in the -I import paths.


Re: /usr/bin/ld: cannot find -lphobos2

2016-03-21 Thread ZombineDev via Digitalmars-d-learn

On Monday, 21 March 2016 at 10:46:27 UTC, ag0aep6g wrote:

On 21.03.2016 11:19, ZombineDev wrote:

DFLAGS=-I~/dev/repos/dlang/druntime/import 
-I~/dev/repos/dlang/phobos

-L-L/home/zombinedev/dev/repos/dlang/phobos/generated/*/release/64

[...]

Linking...
...
/usr/bin/ld {other stuff...}
-L/home/zombinedev/dev/repos/dlang/phobos/generated/*/release/64 -lphobos2
/usr/bin/ld: cannot find -lphobos2

However
$ ls 
/home/zombinedev/dev/repos/dlang/phobos/generated/*/release/64

etc  libphobos2.a  libphobos2.so  libphobos2.so.0.70
libphobos2.so.0.70.0  libphobos2.so.0.70.o

Any idea what I'm doing wrong?


Asterisk expansion is a shell feature. dmd probably doesn't go 
through a shell when running ld.


Even if it did, no expansion would be done there, because the 
word is looked at as a whole. With the leading "-L", the 
pattern doesn't match an actual path. For example, compare 
`echo /*` with `echo -L/*`.


You have to spell the different paths out.


Thanks a lot! I replaced "*" with the name of my OS and it all 
works!
I thought that if it could replace $HOME, it ought to replace the 
asterisk.
Probably I should add this caveat to 
http://wiki.dlang.org/Starting_as_a_Contributor#Running_Independent_Programs for future reference.




Re: /usr/bin/ld: cannot find -lphobos2

2016-03-21 Thread ag0aep6g via Digitalmars-d-learn

On 21.03.2016 11:19, ZombineDev wrote:


DFLAGS=-I~/dev/repos/dlang/druntime/import -I~/dev/repos/dlang/phobos
-L-L/home/zombinedev/dev/repos/dlang/phobos/generated/*/release/64

[...]

Linking...
...
/usr/bin/ld {other stuff...}
-L/home/zombinedev/dev/repos/dlang/phobos/generated/*/release/64 -lphobos2
/usr/bin/ld: cannot find -lphobos2

However
$ ls /home/zombinedev/dev/repos/dlang/phobos/generated/*/release/64
etc  libphobos2.a  libphobos2.so  libphobos2.so.0.70
libphobos2.so.0.70.0  libphobos2.so.0.70.o

Any idea what I'm doing wrong?


Asterisk expansion is a shell feature. dmd probably doesn't go through a 
shell when running ld.


Even if it did, no expansion would be done there, because the word is 
looked at as a whole. With the leading "-L", the pattern doesn't match 
an actual path. For example, compare `echo /*` with `echo -L/*`.


You have to spell the different paths out.


Re: Enabling Only Top-Level Unittests

2016-03-21 Thread ZombineDev via Digitalmars-d-learn

On Monday, 21 March 2016 at 10:29:36 UTC, Nordlöw wrote:
I want to enable unittests only at the top-level of a module 
compilation.


If I have a module

top.d

that imports

dep1.d
dep2.d
...

which all contain unittests, how do I compile top.d with only 
the unittests for top.d enabled?


I think the easiest solution is to use 
http://dlang.org/spec/traits.html#getUnitTests and to run the 
tests you want manually.


Enabling Only Top-Level Unittests

2016-03-21 Thread Nordlöw via Digitalmars-d-learn
I want to enable unittests only at the top-level of a module 
compilation.


If I have a module

top.d

that imports

dep1.d
dep2.d
...

which all contain unittests, how do I compile top.d with only the 
unittests for top.d enabled?


/usr/bin/ld: cannot find -lphobos2

2016-03-21 Thread ZombineDev via Digitalmars-d-learn

I'm manually building dmd, druntime and phobos like so:

$ cd ~/dev/repos/dlang
$ git clone https://github.com/D-Programming-Language/dmd
$ git clone https://github.com/D-Programming-Language/druntime
$ git clone https://github.com/D-Programming-Language/phobos

$ cd dmd && make -f make -f posix.mak -j4 AUTO_BOOTSTRAP=1
$ cd ../druntime && make -f make -f posix.mak -j4
$ cd ../phobos && make -f make -f posix.mak -j4

$ cat << EOF > ~/dev/repos/dlang/dmd/src/dmd.conf
[Environment]

DFLAGS=-I~/dev/repos/dlang/druntime/import 
-I~/dev/repos/dlang/phobos 
-L-L/home/zombinedev/dev/repos/dlang/phobos/generated/*/release/64

EOF

# required for dub
$ sudo ln -s ~/dev/repos/dlang/dmd/src/dmd /bin/dmd

When my I build my library with dub I can see that dmd.conf is 
detected correctly:

$ cd $myproj

(I added the following to my dub.sdl:
dflags "-v"
lflags "-v")

$ dmd test --verbose
...
Performing "unittest" build using dmd for x86_64.
...
binarydmd
version   v2.070-devel-46cc1c6
config/home/zombinedev/dev/repos/dlang/dmd/src/dmd.conf
...
Linking...
...
/usr/bin/ld {other stuff...} 
-L/home/zombinedev/dev/repos/dlang/phobos/generated/*/release/64 
-lphobos2

/usr/bin/ld: cannot find -lphobos2

However
$ ls 
/home/zombinedev/dev/repos/dlang/phobos/generated/*/release/64
etc  libphobos2.a  libphobos2.so  libphobos2.so.0.70  
libphobos2.so.0.70.0  libphobos2.so.0.70.o


Any idea what I'm doing wrong?


Re: Something wrong with GC

2016-03-21 Thread thedeemon via Digitalmars-d-learn

On Sunday, 20 March 2016 at 07:49:17 UTC, stunaep wrote:
The gc throws invalid memory errors if I use Arrays from 
std.container.


Those arrays are for RAII-style deterministic memory release, 
they shouldn't be freely mixed with GC-allocated things. What 
happens here is while initializing Array sees it got some GC-ed 
value type (strings), so it tells GC to look after those strings. 
When your program ends runtime does a GC cycle, finds your Test 
object, calls its destructor that calls Array destructor that 
tries to tell GC not to look at its data anymore. But during a GC 
cycle it's currently illegal to call such GC methods, so it 
throws an error.
Moral of this story: try not to store "managed" (collected by GC) 
types in Array and/or try not to have Arrays inside "managed" 
objects. If Test was a struct instead of a class, it would work 
fine.