February 10, 2009 Re: Proposal : allocations made easier with non nullable types. | ||||
|---|---|---|---|---|
| ||||
Posted in reply to dsimcha | dsimcha wrote: > == Quote from Andrei Alexandrescu (SeeWebsiteForEmail@erdani.org)'s article >> Sure. My suggested framework is one in which you'd use malloc for those >> allocations. Then you can free. But plopping delete in the midst of a GC >> system... that's just uncalled for. >> Andrei > > But then, you can't delete, for example, builtin arrays. You oughtn't. > Furthermore, if you use > C's malloc/free, you have to be really anal about making sure all code paths free > the memory. I agree. But the underlying idea is that those places are few and far apart. > With the ability to manually free GC managed memory, it becomes ok to > miss an infrequently taken code path, like an exception, because it's just a > performance optimization. The problem is, many (most?) GCs don't support manual deletion. That's a quirk rather endemic to D's implementation. Relying on it is not wise because other allocators will implement it as a do-nothing. But the real problem is that delete creates a safety hole. I'd rather keep at least the GC heap as free from corruption as possible. > Lastly, using multiple heaps like this seems kind of > inefficient. There could be tons of free space on the GC heap, and you'd still be > allocating on the C heap. > > I think it's fine to remove the delete keyword, but at least keep the GC.free > library function. IMHO that is too unsafe for any of these arguments to convince me. Andrei | |||
February 10, 2009 Re: Proposal : allocations made easier with non nullable types. | ||||
|---|---|---|---|---|
| ||||
Posted in reply to Andrei Alexandrescu | Besides safety concerns, what does forbidding manual deletion enable GC implementations to do? | |||
February 10, 2009 Re: Proposal : allocations made easier with non nullable types. | ||||
|---|---|---|---|---|
| ||||
Posted in reply to Chad J | Chad J wrote:
> Besides safety concerns, what does forbidding manual deletion enable GC
> implementations to do?
Foregoing delete affords the GC more implementation options.
Andrei
| |||
February 10, 2009 Re: Proposal : allocations made easier with non nullable types. | ||||
|---|---|---|---|---|
| ||||
Posted in reply to Andrei Alexandrescu | Andrei Alexandrescu wrote:
> Chad J wrote:
>> Besides safety concerns, what does forbidding manual deletion enable GC implementations to do?
>
> Foregoing delete affords the GC more implementation options.
>
> Andrei
Such as?
I'm not trying to be antagonistic--manual deletion is a nifty feature to me, so if it gets designed away I'd appreciate knowing what great advantages justified such a sacrifice.
| |||
February 10, 2009 Re: Proposal : allocations made easier with non nullable types. | ||||
|---|---|---|---|---|
| ||||
Posted in reply to Andrei Alexandrescu | == Quote from Andrei Alexandrescu (SeeWebsiteForEmail@erdani.org)'s article > Chad J wrote: > > Besides safety concerns, what does forbidding manual deletion enable GC implementations to do? > Foregoing delete affords the GC more implementation options. Andrei Let's assume this is true and that these options are things that are useful to a language like D. Worst case scenario, a GC implementation could just ignore calls to GC.free(). GC.free() could just be implementation defined as either frees memory or does nothing. As far as safety, D is a systems programming language. If you really want to manually delete a piece of GC-allocated memory, you should be able to. It's good for a systems language to make it harder to screw up _by accident_ (I'm all for getting rid of the delete keyword to make deleting GC-allocated memory less obvious), but if you insist on doing something, the language should assume you have a good reason. Deleting GC allocated memory is an advanced technique that you do at your own risk, just like using C's malloc/free, using pointers, turning off bounds checking, casting, using inline assembly, not initializing variables at declaration, and all the other dangerous but sometimes useful stuff that "safe" languages won't let you do. Disabling this wouldn't absolutely prevent corruption of the GC heap since D still has pointers, which in principle could be made to point anywhere, and since one could still do something stupid like store the only pointer to an object in a region not scanned by the GC via casting or something. The bottom line is that I fail to see how deleting GC-allocated memory is any different than other dangerous but useful things that can be done in D, and unless we want to make D a completely safe language at the expense of the flexibility that its unsafeness offers, I don't understand why you're so opposed to it. | |||
February 10, 2009 Re: Proposal : allocations made easier with non nullable types. | ||||
|---|---|---|---|---|
| ||||
Posted in reply to Chad J | Chad J wrote:
> Andrei Alexandrescu wrote:
>> Chad J wrote:
>>> Besides safety concerns, what does forbidding manual deletion enable GC
>>> implementations to do?
>> Foregoing delete affords the GC more implementation options.
>>
>> Andrei
>
> Such as?
>
> I'm not trying to be antagonistic--manual deletion is a nifty feature to
> me, so if it gets designed away I'd appreciate knowing what great
> advantages justified such a sacrifice.
You need to simply go through a good tutorial on GC implementations, and consider the added costs of offering a manual delete primitive.
Andrei
| |||
February 10, 2009 Re: Proposal : allocations made easier with non nullable types. | ||||
|---|---|---|---|---|
| ||||
Posted in reply to dsimcha | dsimcha wrote: > == Quote from Andrei Alexandrescu (SeeWebsiteForEmail@erdani.org)'s article >> Chad J wrote: >>> Besides safety concerns, what does forbidding manual deletion enable GC >>> implementations to do? >> Foregoing delete affords the GC more implementation options. >> Andrei > > Let's assume this is true and that these options are things that are useful to a > language like D. Worst case scenario, a GC implementation could just ignore calls > to GC.free(). GC.free() could just be implementation defined as either frees > memory or does nothing. Sure, but making GC.free() offer no guarantee makes it rather useless. It's actually worse than useless because you see a call to GC and you don't know whether or not that could mess up your heap, and you also don't know whether or not that can get you any memory. > As far as safety, D is a systems programming language. If you really want to > manually delete a piece of GC-allocated memory, you should be able to. It's good > for a systems language to make it harder to screw up _by accident_ (I'm all for > getting rid of the delete keyword to make deleting GC-allocated memory less > obvious), but if you insist on doing something, the language should assume you > have a good reason. Deleting GC allocated memory is an advanced technique that > you do at your own risk, just like using C's malloc/free, using pointers, turning > off bounds checking, casting, using inline assembly, not initializing variables at > declaration, and all the other dangerous but sometimes useful stuff that "safe" > languages won't let you do. Disabling this wouldn't absolutely prevent corruption > of the GC heap since D still has pointers, which in principle could be made to > point anywhere, and since one could still do something stupid like store the only > pointer to an object in a region not scanned by the GC via casting or something. > The bottom line is that I fail to see how deleting GC-allocated memory is any > different than other dangerous but useful things that can be done in D, and unless > we want to make D a completely safe language at the expense of the flexibility > that its unsafeness offers, I don't understand why you're so opposed to it. Because you have malloc. If you didn't, I'd be all with you. Just use malloc and leave the GC heap alone. It's the perfect setup. Andrei | |||
February 10, 2009 Re: Proposal : allocations made easier with non nullable types. | ||||
|---|---|---|---|---|
| ||||
Posted in reply to Daniel Keep | "Daniel Keep" <daniel.keep.lists@gmail.com> wrote in message news:gmpd71$8uj$1@digitalmars.com... > Alex Burton wrote: >> I think it makes no sense to have nullable pointers in a high level language like D. > > Oh, and how do you intend to make linked lists? Or trees? Or any non-trivial data structure? > Null Object Pattern: -------------- class LinkedListNode(T) { LinkedListNode!(T) next; private static LinkedListNode!(T) _end; static LinkedListNode!(T) end() { return _end; } static this() { _end = new LinkedListNode!(T); } } -------------- However, I admit this is little more than re-inventing null. But it's at least possible. > Saying they have no place in a language is just silly; the question should be whether they should be the default or not (I would contend that they shouldn't be.) > Agreed. >> In D : >> >> X x = new X; >> This is a bit redundant, if we take away the ability to write X x; to >> mean X x = 0; then we can have X x; mean X x = new X; >> If the class has a ctor then we can write X x(32); instead of X x = new >> X(32); > > Can I just say that I *LOATHE* this syntax? It's one thing I always despised about C++; it simply makes NO sense whatsoever. It looks like the bastard offspring of a function declaration and a function call. > > The first *is* redundant, but then I wouldn't state X twice, I'd use "auto" (because types are almost never a single letter anyway.) Add to that that the existing syntax is much more intuitive; it even reads like a sentence. > Just a thought: Would you hate this less: X(32) x; >> Only when the types of the pointer and class are different do we need to >> write X x = new Y; >> We can do this syntactically in D because classes cannot be instantiated >> on the stack (unless scope is used, which I have found a bit pointless, >> as members are not scope so no deterministic dtor) > > I made a proposal quite some time ago detailing how we could have not only scope members of classes, but even scope RETURN values, but I think it got maybe one reply... :P > > Given that one of D's tenets is to make it simpler to write deterministic, bullet-proof code, the complete lack of deterministic destruction of classes has always felt like a huge hole in the language. > I don't suppose you have a link or the subject line of that handy? >> As I said in the nullable types thread: >> Passing 0 or 0x012345A or anything else that is not a pointer to an >> instance of X to a variable declared as X x is the same as mixing in a >> bicycle when a recipe asks for a cup of olive oil. > > Passing garbage to a function doesn't have any bearing on the non-nullable discussion. If you're casting random integers to pointers and passing them to functions, you reap what you sow. :) > > That said, passing null is more like omitting an ingredient. Which is unfortunate if you're making soup and the ingredient is "water." > I have to say, I'm loving these analogies :-) > While I'm a strong believer in non-nullable types, I don't think null pointers are evil. They're a tool like anything else; problems only arise when you misue them. > > I believe they're the wrong default choice, because they don't come up in normal code, but you've got to fall over yourself to make sure they don't become an issue. > That's pretty much my opinion on the matter as well. Null Object Pattern is a usable alternative to nullables, and even more powerful (the "null" is capable of functions, data and polymorphism), but in the cases when you don't need that extra power, a non-default nullable is just less work and isn't really any less safe. > Eventually, I tracked it down to one of the few places in the code that I forgot to assert the reference was non-null. It was null because Microsoft didn't bother to document that a particular "magic object" doesn't exist until a certain point. > C#/.NET does seem to have some odd quirks like that. A few weeks ago, I was pulling my hair out figuring out a particular bug, and stepping through in the debugger only perplexed me more. Turned out there was an object with a property I was setting, but the new value was somehow "queued" and didn't actually take until later on. The docs hadn't mentioned that particular behavior. | |||
February 10, 2009 Re: Proposal : allocations made easier with non nullable types. | ||||
|---|---|---|---|---|
| ||||
Posted in reply to grauzone | "grauzone" <none@example.net> wrote in message news:gmpe6g$adf$2@digitalmars.com... > Alex Burton wrote: > > For structs, use opCall() to initialize them. opCall is the best way to initialize a struct, because struct literal are totally utterly useless. > > If you use opCall to initialize classes as well (see above), then the syntax for initializing structs and classes will be exactly the same. > That's good advice for using D today, but it's still subject to human error. Making "X x;" serve as an implicit "X x = new X();" for classes would eliminate that human error. | |||
February 10, 2009 Re: Proposal : allocations made easier with non nullable types. | ||||
|---|---|---|---|---|
| ||||
Posted in reply to Nick Sabalausky | Nick Sabalausky wrote: > "Daniel Keep" <daniel.keep.lists@gmail.com> wrote in message news:gmpd71$8uj$1@digitalmars.com... >> Alex Burton wrote: >>> I think it makes no sense to have nullable pointers in a high level language like D. >> Oh, and how do you intend to make linked lists? Or trees? Or any non-trivial data structure? >> > > Null Object Pattern: > -------------- > class LinkedListNode(T) > { > LinkedListNode!(T) next; > > private static LinkedListNode!(T) _end; > static LinkedListNode!(T) end() { > return _end; > } > static this() { > _end = new LinkedListNode!(T); > } > } > -------------- > > However, I admit this is little more than re-inventing null. But it's at least possible. And don't forget that in doing this, you've lost the benefit of dereferencing a null crashing the program: if you accidentally access the _end member, you won't notice unless you explicitly check for it. >> [snip] >>> In D : >>> >>> ... we can write X x(32); instead of X x = new >>> X(32); >> Can I just say that I *LOATHE* this syntax? It's one thing I always despised about C++; it simply makes NO sense whatsoever. It looks like the bastard offspring of a function declaration and a function call. >> >> ... > > Just a thought: Would you hate this less: > X(32) x; That's just as bad; it looks like a parameterised type where you forgot the '!'. >> I made a proposal quite some time ago detailing how we could have not only scope members of classes, but even scope RETURN values, but I think it got maybe one reply... :P >> >> Given that one of D's tenets is to make it simpler to write deterministic, bullet-proof code, the complete lack of deterministic destruction of classes has always felt like a huge hole in the language. > > I don't suppose you have a link or the subject line of that handy? Took me a while to find it, even knowing what it was about. Ended up having to manually go through the digitalmars.com archives. :P http://www.digitalmars.com/d/archives/digitalmars/D/38329.html It's probably somewhat anachronistic now. For anyone who isn't aware, back in the old days, 'scope' was 'auto' whilst 'auto' was 'auto.' It sort of did two things and was a bit confusing. Just replace 'auto' with 'scope' and you should be fine. :P Also, back then auto didn't stack-allocate. If I may digress to the land of make-believe for a moment: if this proposal was implemented, you could get around the whole "stack allocation" thing like this: { scope X foo() { return new X; } scope X x = foo(); } Which could become this: { void foo(ubyte[] storage, inout X ptr) { static if( X.sizeofinstance > storage.length ) { ptr = new X; } else { storage[0..X.sizeofinstance] = cast(ubyte[])(new X); } } ubyte[X.sizeofinstance] x_storage; scope X x = x_storage.ptr; foo(x_storage, x); } The caller allocates enough space for an instance of X and passes both the storage and the actual reference variable. The caller can then either store the instance in that array, or make the reference point to somewhere else. Just a thought. :P </digression> >> [snip] >> While I'm a strong believer in non-nullable types, I don't think null >> pointers are evil. They're a tool like anything else; problems only >> arise when you misue them. >> >> I believe they're the wrong default choice, because they don't come up in normal code, but you've got to fall over yourself to make sure they don't become an issue. >> > > That's pretty much my opinion on the matter as well. Null Object Pattern is a usable alternative to nullables, and even more powerful (the "null" is capable of functions, data and polymorphism), but in the cases when you don't need that extra power, a non-default nullable is just less work and isn't really any less safe. I'd argue it's more safe because it'll crash your program faster. :D >> Eventually, I tracked it down to one of the few places in the code that I forgot to assert the reference was non-null. It was null because Microsoft didn't bother to document that a particular "magic object" doesn't exist until a certain point. > > C#/.NET does seem to have some odd quirks like that. A few weeks ago, I was pulling my hair out figuring out a particular bug, and stepping through in the debugger only perplexed me more. Turned out there was an object with a property I was setting, but the new value was somehow "queued" and didn't actually take until later on. The docs hadn't mentioned that particular behavior. Microsoft just seems to be really bad at documentation. They go to all that effort of creating a tremendous amount of documentation, but don't succeed in actually saying anything. My favourites are the innumerable classes in .NET or XNA that document every single member function and property... but fail to state what any of them ACTUALLY DO. Or what the arguments are for. Or what the valid values are. Or under what circumstances it's usable. Or how to even create the bloody things. -- Daniel | |||
Copyright © 1999-2021 by the D Language Foundation
Permalink
Reply