April 23, 2009
Andrei Alexandrescu, el 23 de abril a las 05:58 me escribiste:
> I've discussed something with Walter today and thought I'd share it here.
> 
> The possibility of using D without a garbage collector was always looming and has been used to placate naysayers ("you can call malloc if you want" etc.) but that opportunity has not been realized in a seamless manner. As soon as you concatenate arrays, add to a hash, or create an object, you will call into the GC.
> 
> So I'm thinking there should be a flag -nogc that enables a different model of memory allocation. Here's the steps we need to take:
> 
> 1. Put array definitions in object.d. Have the compiler rewrite "T[]" ->
> ".Array!(T)" and "[ a, b, c ]" -> ".Array!(typeof(a))(a, b, c)". I think
> superdan suggested that when he wasn't busy cursing :o).
> 
> 2. Do the similar thing for associative arrays.
> 
> 3. Have two object.d at hand: one is "normal" and uses garbage collection, the other (call it object_nogc.d) has an entirely different definition for arrays, hashes, and Object.
> 
> 4. The definition of Object in object_nogc.d includes a reference count member for intrusive refcounting.
> 
> 5. Define a Ref!(T) struct in object_nogc.d that does intrusive reference counting against T using ctors and dtor.

Oh! So you mean -nomarksweep then, right? Rerence counting *is* a garbage collection algorithm.

> 6. At this point we already have a usable, credible no-gc offering: just
> use object_nogc.d instead of object.d and instead of "new Widget(args)"
> use "Ref!(Widget)(args)".
> 
> 7. Add a -nogc option to the compiler. In that mode, the compiler
> replaces automatically "T" -> "Ref!(T)" and "new T(args)" ->
> "Ref!(T)(args)" for all classes T except inside
> object_nogc.d. The exception, as Walter pointed out, is to avoid
> infinite regression (how do you implement Ref if the reference you hold
> inside will also be wrapped in Ref???)
> 
> 8. Well with this all a very solid offering of D without garbage collection would be available at a low cost!

Besides this not being "non gc D", seems like a good idea. If I know there were any chance that RC had a chance to be accepted in the D, I would included it in my thesis.

> One cool thing is that you can compile the same application with and without GC and test the differences easily. That's bound to show a number of interesting things!

Please, stop calling it "without GC", is really confusing =)

-- 
Leandro Lucarella (luca) | Blog colectivo: http://www.mazziblog.com.ar/blog/
----------------------------------------------------------------------------
GPG Key: 5F5A8D05 (F8CD F9A7 BF00 5431 4145  104C 949E BFB6 5F5A 8D05)
----------------------------------------------------------------------------
April 23, 2009
bearophile, el 23 de abril a las 07:08 me escribiste:
> Andrei Alexandrescu:
> > The possibility of using D without a garbage collector was always looming and has been used to placate naysayers ("you can call malloc if you want" etc.) but that opportunity has not been realized in a seamless manner. As soon as you concatenate arrays, add to a hash, or create an object, you will call into the GC.
> 
> One simple possible solution: -nogc is to write C-like programs, with no
> automatic reference counting. It doesn't include the GC in the final
> executable (making it much smaller) and in such programs AAs and array
> concatenation and closures are forbidden (compilation error if you try
> to use them). "New" allocates using the C heap, and you have to use
> "delete" manually for each of them.  This is simple. While adding
> a second memory management system, ref-counted, looks like an increase
> of complexity for both the compiler and the programmers.

I definitely agree that -nogc should not imply reference counting garbarge collection.

Now in Tango/Druntime you already can use a dummy GC that all it does is calling C malloc/free for gc_malloc/gc_free, exactly for this purpose, so what -nogc should do in that case is just link against the "stub" GC instead to the "basic".

> >1. Put array definitions in object.d. Have the compiler rewrite "T[]" -> ".Array!(T)"<
> 
> That has to be done with care an in a transparent way, not adding the Array name in the namespace, so you can create an Array youself, etc.

srd.array.Array can be used, and leave T[] as a syntax sugar only (but you
could also write std.array.Array!(T) instead).

-- 
Leandro Lucarella (luca) | Blog colectivo: http://www.mazziblog.com.ar/blog/
----------------------------------------------------------------------------
GPG Key: 5F5A8D05 (F8CD F9A7 BF00 5431 4145  104C 949E BFB6 5F5A 8D05)
----------------------------------------------------------------------------
April 23, 2009
bearophile wrote:
> Making things more orthogonal can be quite useful and it allows more flexibility, but having common things implemented as magic is sometimes good because you need less knowledge to use the language, you need less time to understand code written by other people (because there are less general ways to do something), and this allows for more sharing of code, and you may cover most of the common usages anyway. So the risk of making things more orthogonal is to over-generalize. Scheme language (that is very orthogonal) shows this failure very well, this is a related quotation:
> 
>> In practice Scheme follows exactly the opposite route: there are dozens of different and redundant object systems, module systems, even record systems, built just by piling up feature over feature. So the minimalism of the core language is just a lie or at best a red herring (the core language can be minimalistic, but the core language is basically useless for any real life job).<

The difference here is that a core of these semi-magic features is
standard.  You’ll never write “std.Array!(T)” in real code; you’d use
“T[]”.  You might still replace the core library with custom versions of
Object &c., but you ought not to be tempted to do so.

—Joel Salomon
April 23, 2009
Andrei Alexandrescu Wrote:

> Jason House wrote:
> > Andrei Alexandrescu Wrote:
> > 
> >> I've discussed something with Walter today and thought I'd share it here.
> >>
> >> The possibility of using D without a garbage collector was always looming and has been used to placate naysayers ("you can call malloc if you want" etc.) but that opportunity has not been realized in a seamless manner. As soon as you concatenate arrays, add to a hash, or create an object, you will call into the GC.
> >>
> >> So I'm thinking there should be a flag -nogc that enables a different model of memory allocation. Here's the steps we need to take:
> >>
> >> 1. Put array definitions in object.d. Have the compiler rewrite "T[]" ->
> >> ".Array!(T)" and "[ a, b, c ]" -> ".Array!(typeof(a))(a, b, c)". I think
> >> superdan suggested that when he wasn't busy cursing :o).
> > 
> > I like that translation since it can allow customization. How will the type system handle Array!(const(T)) and const(Array!T)? They're no longer implicitly convertible.
> 
> We will need to accommodate multiple implicit conversions somehow anyway (e.g. multiple alias this entries). This is a great question because it illustrates how segregating arrays out of the language challenges the magic that made them "special" and democratizes good features such that other types can benefit of them too.

This is something I've given thought to in the past. The basic requirement for x!(const(T),U) to be implicitly convertible to const(x!(T,U)) is:
1. Member variables match in physical loxation, quantity.
2. Member variables in both x!(T,U) and x!(const(T),U) are both implicitly convertible to normal const versions
3. Const member functions must have identical behavior






> >> 2. Do the similar thing for associative arrays.
> >>
> >> 3. Have two object.d at hand: one is "normal" and uses garbage collection, the other (call it object_nogc.d) has an entirely different definition for arrays, hashes, and Object.
> > 
> > A version statement seems more powerful. Standard libraries may need changes too.
> > 
> >> 4. The definition of Object in object_nogc.d includes a reference count member for intrusive refcounting.
> > 
> > That's still a method of garbage collecting! -nogc is kind of misleading...
> 
> Yah, I agree.
> 
> >> 5. Define a Ref!(T) struct in object_nogc.d that does intrusive reference counting against T using ctors and dtor.
> >>
> >> 6. At this point we already have a usable, credible no-gc offering: just
> >> use object_nogc.d instead of object.d and instead of "new Widget(args)"
> >> use "Ref!(Widget)(args)".
> > 
> > Ick... Please make this hijack the default new behavior.
> 
> Agreed.
> 
> 
> Andrei

April 23, 2009
Joel C. Salomon wrote:
> Just as (1) & (2) point to a way to remove the “magic” of built-in
> arrays & hash-tables, so too might (5) & (6) point to a way of replacing
> the “new T(args)” syntax with something cleaner?  Not that
> “new!(T)(args)” looks nicer than the current syntax, but is it perhaps a
> better fit with the rest of the language?

I agree. new sucks.

Andrei
April 23, 2009
Georg Wrede wrote:
> Today really seems to be the lucky day of D!
> So many pieces are clicking together!!
> Oh, my!

Also, I just gave my talk on ranges vs. iterators at ACCU. The audience is still "shell shocked" as Walter put it. I guess it went well :o).

Andrei
April 23, 2009
Leandro Lucarella wrote:
> Oh! So you mean -nomarksweep then, right? Rerence counting *is* a garbage
> collection algorithm.

Probably the best way is to express it as a positive:

-object=object_marksweep.d
-object=object_refcount.d
-object=object_generational.d

The point is that changing the relatively small object.d enables various fundamental approaches to allocation.

>> 8. Well with this all a very solid offering of D without garbage
>> collection would be available at a low cost!
> 
> Besides this not being "non gc D", seems like a good idea. If I know there
> were any chance that RC had a chance to be accepted in the D, I would
> included it in my thesis.

Walter?

>> One cool thing is that you can compile the same application with and
>> without GC and test the differences easily. That's bound to show a
>> number of interesting things!
> 
> Please, stop calling it "without GC", is really confusing =)

I agree.


Andrei
April 23, 2009
Leandro Lucarella wrote:

> Now in Tango/Druntime you already can use a dummy GC that all it does is calling C malloc/free for gc_malloc/gc_free, exactly for this purpose, so what -nogc should do in that case is just link against the "stub" GC instead to the "basic".

This claim really needs to stop.  You can't just swap from the normal gc
to the stub gc an expect your app to use malloc/free and behave exactly
as it did before.  No, it'll leak.  Free will never be called (outside
the rare case of an explicit delete).  Normal apps expect implicit
cleanup to be invoked by the gc which will never happen in the stub.
That's fine in tiny apps, or apps that carefully manage their own
memory, but then you weren't using the gc in the first place for those apps.

Later,
Brad
April 23, 2009
Brad Roberts wrote:
> Leandro Lucarella wrote:
> 
>> Now in Tango/Druntime you already can use a dummy GC that all it does is
>> calling C malloc/free for gc_malloc/gc_free, exactly for this purpose, so
>> what -nogc should do in that case is just link against the "stub" GC
>> instead to the "basic".
> 
> This claim really needs to stop.  You can't just swap from the normal gc
> to the stub gc an expect your app to use malloc/free and behave exactly
> as it did before.  No, it'll leak.  Free will never be called (outside
> the rare case of an explicit delete).  Normal apps expect implicit
> cleanup to be invoked by the gc which will never happen in the stub.
> That's fine in tiny apps, or apps that carefully manage their own
> memory, but then you weren't using the gc in the first place for those apps.

Totally agreed. I've always wondered what the purpose of the stub GC was in druntime. "We can implement an appallingly crappy allocation model" is the only message I'm getting.

Andrei
April 23, 2009
Brad Roberts, el 23 de abril a las 10:39 me escribiste:
> Leandro Lucarella wrote:
> 
> > Now in Tango/Druntime you already can use a dummy GC that all it does is calling C malloc/free for gc_malloc/gc_free, exactly for this purpose, so what -nogc should do in that case is just link against the "stub" GC instead to the "basic".
> 
> This claim really needs to stop.  You can't just swap from the normal gc
> to the stub gc an expect your app to use malloc/free and behave exactly
> as it did before.  No, it'll leak.  Free will never be called (outside
> the rare case of an explicit delete).  Normal apps expect implicit
> cleanup to be invoked by the gc which will never happen in the stub.
> That's fine in tiny apps, or apps that carefully manage their own
> memory, but then you weren't using the gc in the first place for those apps.

Maybe it wasn't clear enough (and it's less clear even in you mail where
you remove all context of my response) but what I said was in response to
bearophile mail, which said (and I quote it again):

	One simple possible solution: -nogc is to write C-like programs,
	with no automatic reference counting. It doesn't include the GC in
	the final executable (making it much smaller) and in such programs
	AAs and array concatenation and closures are forbidden
	(compilation error if you try to use them). "New" allocates using
	the C heap, and you have to use "delete" manually for each of
	them.

So, no, I'm not implying that one can use the "stub" GC implementation and just go and be happy and play with dynamic arrays and hashes and expect that memory get freed magically.

Please read the message in its context before putting words in my mouth.

Thanks.

-- 
Leandro Lucarella (luca) | Blog colectivo: http://www.mazziblog.com.ar/blog/
----------------------------------------------------------------------------
GPG Key: 5F5A8D05 (F8CD F9A7 BF00 5431 4145  104C 949E BFB6 5F5A 8D05)
----------------------------------------------------------------------------