September 03, 2012
>>
>> In C++, I often did it with iterators:
>> ----
>> for(it ...)
>> {
>>     int& val = *it;
>>     //now, we can access it with value semantics through val.
>> }
>> ----
>>
>> ?

with(it) should help a lot but here. Still it was bogus back then when I used it with pointers, not sure how good it is now.

>
> Good question, I've proceeded in the same way in C++ many times. I hope
> there's a way, but I think it likely there is not, except by passing *it
> to a function with a reference parameter.
>
>


-- 
Olshansky Dmitry
September 03, 2012
On Monday, 3 September 2012 at 12:12:46 UTC, monarch_dodra wrote:
> I was playing around with a very big struct, and told myself I wanted it allocated on the heap. This meant I was now manipulating S* instead of an S.
>
> I thought "this should have zero impact, because in D, because "." is supposed to deference for you if needed."
>
> I find it strange though that when trying to call a function with a pointer, the pointer isn't automatically dereferenced if needed:
>
> ----
> struct S
> {
>   void foo();
> }
> void bar(S);
> void main()
> {
>   auto r = new S;
>   r.foo();
>   bar(r);  //derp
>   r.bar(); //derp
> };
> ----
> I find it strange, because I thought the entire point was to abstract way something was allocated to the way it was used: EG. From a caller perspective, I don't care if r is on the stack or on the heap: I just want to call the method bar on the object in question.
>
> Why does one consider a "free standing" function more ambiguous than a member function?
>
> Things get even stranger if you mix in uniform call syntax. "r.foo()" works, but "r.bar()" doesn't?
>
> Am I really forced into:
> ----
> struct S
> {
>   void foo();
> }
> void bar(S);
> void main()
> {
>   auto r = new S;
>   r.foo();
>   bar(*r);    //Groan
>   (*r).bar(); //Super Groan.
> };
> ----
> I feel as if I'm just back at square 1...

In a nutshell, I think you're broadly saying that you want to program with a struct S the same way whether it's stack or heap allocated. (Good code reuse, and no duplication of semantics with -> as in C++.) From this perspective the trouble is that "S()" and "new S()" don't have the same effect except for allocating one on the stack and one on the heap, and the language forbids you from overcoming this via reference variables, except by calling a function and passing "*r" to a "ref S" parameter.

So maybe that's what you should do with D in its present state. Once you've passed *r to the real main function for working with your big struct as "ref S", well, after that in all calls it's in value form.

It's useful that "new S()" produces a pointer when building low level data structures in D, and your purpose is to heap-rather-than-stack allocate and proceed as before. These are completely different purposes.

So I'm wondering if a language extension along the following lines would solve your problem, simply asking the compiler to use heap allocation when the variable is declared, e.g.

 @heap auto s = S(); //secretly allocated with new, but used as if local

where the compiler would know that s is valid, just as in a normal declaration. And the compiler would automatically deallocate the variable's heap storage when it goes out of scope. Otherwise the variable would behave like a normal local variable as far as inference of any kind made by the compiler in a wider context goes.


September 03, 2012
On Monday, September 03, 2012 23:19:07 Carl Sturtivant wrote:
> So I'm wondering if a language extension along the following lines would solve your problem,

Whoa. Stop right there. Language extension? If you think that you need a language extension to solve a problem, odds are that you're going about things the wrong way. Sometimes a language extension would indeed be needed to do something, but odds are, it's not. D is a very powerful language. Think long and hard about how to do something _within_ the language before you even consider extending it.

If all you're looking to do is make it so that you don't have to care whether you're dealing with an S or S*, then a language extension is complete overkill. Just make a wrapper struct. Something like (untested):

struct Wrapper(T)
{
    T* ptr;

    ref inout(T) get() inout { return *ptr; }

    alias get this;
}

Just wrap an S* in that, and you can use it exactly as if it were an S. Problem solved.

- Jonathan M Davis
September 03, 2012
On Monday, 3 September 2012 at 21:44:15 UTC, Jonathan M Davis
wrote:
> On Monday, September 03, 2012 23:19:07 Carl Sturtivant wrote:
>> So I'm wondering if a language extension along the following
>> lines would solve your problem,
>
> Whoa. Stop right there. Language extension? If you think that you need a
> language extension to solve a problem, odds are that you're going about things
> the wrong way. Sometimes a language extension would indeed be needed to do
> something, but odds are, it's not. D is a very powerful language. Think long
> and hard about how to do something _within_ the language before you even
> consider extending it.
>
> If all you're looking to do is make it so that you don't have to care whether
> you're dealing with an S or S*, then a language extension is complete
> overkill. Just make a wrapper struct. Something like (untested):
>
> struct Wrapper(T)
> {
>     T* ptr;
>
>     ref inout(T) get() inout { return *ptr; }
>
>     alias get this;
> }
>
> Just wrap an S* in that, and you can use it exactly as if it were an S.
> Problem solved.
>
> - Jonathan M Davis

---same thing (specialized to struct S) in my first reply.
I'm just fishing, seeking a boundary.

There is a cleanness issue to discuss. It would be nice to know
what you think about implicit conversion from 'S*' to 'ref S'
(and not the other way as someone seemed to be suggesting). It's
hard for a newish outsider to get a sense of where the boundaries
lie.


September 03, 2012
On Tuesday, September 04, 2012 00:21:53 Carl Sturtivant wrote:
> ---same thing (specialized to struct S) in my first reply.
> I'm just fishing, seeking a boundary.
> 
> There is a cleanness issue to discuss. It would be nice to know what you think about implicit conversion from 'S*' to 'ref S' (and not the other way as someone seemed to be suggesting).

Pointers and ref are two entirely different things and shouldn't be treated the same. If you want to pass the pointer to ref S, then dereference it. Any and all implicit conversions should be treated with care. D has far fewer than C/C++ specifically because they're a major source of bugs.

> It's hard for a newish outsider to get a sense of where the boundaries lie.

We're trying _not_ to add new features. D is supposed to be stabilizing. The language definition is essentially frozen. We pretty much only add features when we really need to. Any and all new language features need to solve a real problem and need to carry their weight. If anything, the trend is to _remove_ features from the language and move them into the library rather than add them to the language (e.g. scope on local variables being axed in favor of std.typecons.Scoped). You need a _really_ good reason for a new language feature, or it's not going to happen.

Pretty much the only feature that was added at all recently which had anything to do with syntactic niceties was UFCS, and that was extension of an existing feature with arrays, long sought-after, and depending on how you read TDPL, it implied that the feature was in the language. So, it got added. But in general, something that's trying to adjust syntax isn't going to happen, because that's a matter of aesthetics.

_Always_ look to solve the problem within the language first. If you can, then it's _highly_ unlikely that your problem merits a new language feature.

- Jonathan M Davis
September 03, 2012
On Monday, 3 September 2012 at 22:38:28 UTC, Jonathan M Davis wrote:
> On Tuesday, September 04, 2012 00:21:53 Carl Sturtivant wrote:
>> ---same thing (specialized to struct S) in my first reply.
>> I'm just fishing, seeking a boundary.
>> 
>> There is a cleanness issue to discuss. It would be nice to know
>> what you think about implicit conversion from 'S*' to 'ref S'
>> (and not the other way as someone seemed to be suggesting).
>
> Pointers and ref are two entirely different things and shouldn't be treated the
> same. If you want to pass the pointer to ref S, then dereference it. Any and
> all implicit conversions should be treated with care. D has far fewer than
> C/C++ specifically because they're a major source of bugs.
>
>> It's hard for a newish outsider to get a sense of where the boundaries
>> lie.
>
> We're trying _not_ to add new features. D is supposed to be stabilizing. The
> language definition is essentially frozen. We pretty much only add features
> when we really need to. Any and all new language features need to solve a real
> problem and need to carry their weight. If anything, the trend is to _remove_
> features from the language and move them into the library rather than add them
> to the language (e.g. scope on local variables being axed in favor of
> std.typecons.Scoped). You need a _really_ good reason for a new language
> feature, or it's not going to happen.
>
> Pretty much the only feature that was added at all recently which had anything
> to do with syntactic niceties was UFCS, and that was extension of an existing
> feature with arrays, long sought-after, and depending on how you read TDPL, it
> implied that the feature was in the language. So, it got added. But in
> general, something that's trying to adjust syntax isn't going to happen,
> because that's a matter of aesthetics.
>
> _Always_ look to solve the problem within the language first. If you can, then
> it's _highly_ unlikely that your problem merits a new language feature.
>
> - Jonathan M Davis

Thank you for your frankness. The above being the case, I wonder why p.frog where p is a pointer has been made to work when a wrapper will do the job. Is that something that might best be removed? It is after all an aesthetic matter.


September 03, 2012
On Tuesday, September 04, 2012 00:49:48 Carl Sturtivant wrote:
> Thank you for your frankness. The above being the case, I wonder why p.frog where p is a pointer has been made to work when a wrapper will do the job. Is that something that might best be removed? It is after all an aesthetic matter.

You mean getting rid of the automatic pointer dereferencing, making you do (*p).frog instead of p.frog?

Well, regardless of the merits of one or the other, changing it would break code. The decisions for that were made ages ago. It doesn't merit revisiting at this point.

And it's not that aesthetics don't matter. It's that they matter very little in comparison to other things, and given that changing them breaks code and given where we are in D's development, making such changes doesn't generally make sense. They needed to have been decided when the language was much younger and still in flux. As it is, it's mostly frozen, and we're looking to achieve full stability so that people can count on their D code continuing to compile.

Changes which break code need a _really_ good reason to be made, and even if a change doesn't break code, we're not looking to complicate the language further if we don't need to. Also, the more things that get added, the less stable the compiler will be (at least in the short term) and the less work that gets put into fixing what we already have.

D is past the point where we're looking to actively work on and change its design. We want it to be stable and useable like you get with mainstream languages like C++ or Java (only with the benefits of D's features of course). Adding more features (even if they're backwards compatible) distracts from that, and making breaking feature changes goes completely against it.

I'm sure that once the compiler is more stable and all of the features that we already have work appropriately that we'll be more open to adding backwards compatible features (e.g. user-defined attributes). But this is just about the worst time in D's development to ask for features, because we're past the point of freezing the initial design but not yet stable enough to seriously consider adding additional, backwards-compatible features. So, new feature requests really need to pull their weight.

- Jonathan M Davis
September 04, 2012
On Monday, 3 September 2012 at 23:13:26 UTC, Jonathan M Davis
wrote:
> On Tuesday, September 04, 2012 00:49:48 Carl Sturtivant wrote:
>> Thank you for your frankness. The above being the case, I wonder
>> why p.frog where p is a pointer has been made to work when a
>> wrapper will do the job. Is that something that might best be
>> removed? It is after all an aesthetic matter.
>
> You mean getting rid of the automatic pointer dereferencing, making you do
> (*p).frog instead of p.frog?
>
> Well, regardless of the merits of one or the other, changing it would break
> code. The decisions for that were made ages ago. It doesn't merit revisiting
> at this point.
>
> And it's not that aesthetics don't matter. It's that they matter very little
> in comparison to other things, and given that changing them breaks code and
> given where we are in D's development, making such changes doesn't generally
> make sense. They needed to have been decided when the language was much
> younger and still in flux. As it is, it's mostly frozen, and we're looking to
> achieve full stability so that people can count on their D code continuing to
> compile.
>
> Changes which break code need a _really_ good reason to be made, and even if a
> change doesn't break code, we're not looking to complicate the language
> further if we don't need to. Also, the more things that get added, the less
> stable the compiler will be (at least in the short term) and the less work
> that gets put into fixing what we already have.
>
> D is past the point where we're looking to actively work on and change its
> design. We want it to be stable and useable like you get with mainstream
> languages like C++ or Java (only with the benefits of D's features of course).
> Adding more features (even if they're backwards compatible) distracts from
> that, and making breaking feature changes goes completely against it.
>
> I'm sure that once the compiler is more stable and all of the features that we
> already have work appropriately that we'll be more open to adding backwards
> compatible features (e.g. user-defined attributes). But this is just about the
> worst time in D's development to ask for features, because we're past the
> point of freezing the initial design but not yet stable enough to seriously
> consider adding additional, backwards-compatible features. So, new feature
> requests really need to pull their weight.
>
> - Jonathan M Davis

Understood, and again thanks for speaking overtly and frankly
about this.

So in practical terms for this thread's issue, only the corner
case is relevant at this point, of whether '.' as a courtesy
might compile a call of bar(S s, int i) when p.bar(3) is written
and p is of type S* --- and if the usual struct pointer courtesy
for '.' is definitely in the language, then having this as well
does seem more uniform. I hope it goes through. (Plus it helps to
have somewhat reasonable explanations of what can and cannot be
done to supply to students of programming: uniform rules help.)

September 04, 2012
On Monday, September 03, 2012 14:13:10 monarch_dodra wrote:
> I was playing around with a very big struct, and told myself I wanted it allocated on the heap. This meant I was now manipulating S* instead of an S.
[snip]

Enhancement Request:

http://d.puremagic.com/issues/show_bug.cgi?id=8616

- Jonathan M Davis
September 04, 2012
On Mon, 03 Sep 2012 21:04:56 +0100, Era Scarecrow <rtcvb32@yahoo.com> wrote:

> On Monday, 3 September 2012 at 18:45:42 UTC, Jonathan M Davis wrote:
>> However, one thing to remember that complicates this a bit is that it's perfectly possible to declare a function which is overloaded with one function taking a pointer and one not.
>>
>> void func(S* s, int i) {...}
>> void func(S s, int i) {...}
>>
>> in which case, there's an ambiguity, and I would then expect UFCS to _not_ compile when using S*, or you'd risk function call hijacking. That's not necessarily a big deal, but it _does_ complicate things a bit.
>>
>> - Jonathan M Davis
>
>   I think moreso is would if it would convert to ref automatically or not rather than worry about pointers. True if you wanted all three, then the language has to keep them all distinctly different; But if it silently converts it should be okay (so long as constness/immutable is honored). Assuming that's the case:
>
>    //these two effectively identical
>    void func(S* s, int i) {...}
>    void func(ref S s, int i) {...}

What if the first function is in library A and the 2nd function in library B and they do two totally different things?

R

-- 
Using Opera's revolutionary email client: http://www.opera.com/mail/