May 10, 2023
On Wed, May 10, 2023 at 07:56:10PM +0000, Chris Piker via Digitalmars-d-learn wrote: [...]
> My problem with the terms lvalue and rvalue is much more basic, and is just a personal one that only affects probably 0.1% of people.  I just can't keep left vs. right straight in real life.  "Right" in my head always means "correct".
> 
> My daughter hates it when I'm telling her which way to turn the car since I've said the wrong direction so many times. :)

I also suffer from left/right confusion, and always have to pause to think about which is the right(!) word before uttering it. :-D  Would compass directions be more helpful? (wvalue vs. evalue) Or would it suffer from the same problem?

(One could retroactively rationalize it as *w*ritable value vs.
*e*phemeral value. :-P)


T

-- 
By understanding a machine-oriented language, the programmer will tend to use a much more efficient method; it is much closer to reality. -- D. Knuth
May 10, 2023
On Wednesday, 10 May 2023 at 20:25:48 UTC, H. S. Teoh wrote:
> On Wed, May 10, 2023 at 07:56:10PM +0000, Chris Piker via Digitalmars-d-learn wrote: [...]
> I also suffer from left/right confusion, and always have to pause to think about which is the right(!) word before uttering it.
Oh, I though was the only one with that difficulty.  Glad to hear I'm not alone. :-)

I have a tendency to think of things by their purpose when programming but not by their location on the line or page.  So terms such as "writable" versus "ephemeral" or "addressable" versus "temporary" (or "register"), make so much more sense to me.

Back on the ref issue for a moment... I'd imagine that asking the compiler to delay creating a writable variable until it finds out that a storage location is actually needed by subsequent statements, is a tall order. So D chose to introduce programmers to lvalues and rvalues head-on, instead of creating a leaky abstraction.
May 10, 2023
On Wed, May 10, 2023 at 10:57:13PM +0000, Chris Piker via Digitalmars-d-learn wrote:
> On Wednesday, 10 May 2023 at 20:25:48 UTC, H. S. Teoh wrote:
> > On Wed, May 10, 2023 at 07:56:10PM +0000, Chris Piker via
> > Digitalmars-d-learn wrote: [...]
> > I also suffer from left/right confusion, and always have to pause to
> > think about which is the right(!) word before uttering it.
> Oh, I though was the only one with that difficulty.  Glad to hear I'm not alone. :-)

:-)


> I have a tendency to think of things by their purpose when programming but not by their location on the line or page.  So terms such as "writable" versus "ephemeral" or "addressable" versus "temporary" (or "register"), make so much more sense to me.

Yeah TBH I was never a fan of the lvalue/rvalue terminology. In a hypothetical language where the arguments to an assignment operator is reversed, the terminology would become needlessly confusing. E.g., if there was an operator `X => Y;` that means "assign the value of X to Y", then the roles of lvalues/rvalues would be reversed.


> Back on the ref issue for a moment... I'd imagine that asking the compiler to delay creating a writable variable until it finds out that a storage location is actually needed by subsequent statements, is a tall order. So D chose to introduce programmers to lvalues and rvalues head-on, instead of creating a leaky abstraction.

It depends on how you look at it. The very concept of a variable in memory is actually already an abstraction. Modern compilers may enregister variables or even completely elide them. Assignments may be reordered, and the CPU may execute things out-of-order (as long as semantics are preserved). Intermediate values may not get stored at all, but get folded into the larger computation and perhaps merged with some other operation with the resulting compound operation mapped to a single CPU instruction, etc.. So in that sense the compiler is quite capable of figuring out what to do...

But what it can't do is read the programmer's mind to deduce the intent of his code. Exact semantics must be somehow conveyed to the compiler, and sad to say humans aren't very good at being exact. Often we *think* we know exactly what the computation is, but in reality we gloss over low-level details that will make a big difference in the outcome of the computation in the corner cases. The whole rvalue/lvalue business is really more a way of conveying to the compiler what exactly must happen, rather than directly corresponding to any actual feature in the underlying physical machine.


T

-- 
Computerese Irregular Verb Conjugation: I have preferences.  You have biases.  He/She has prejudices. -- Gene Wirchenko
May 12, 2023

On Sunday, 7 May 2023 at 21:04:05 UTC, Inkrementator wrote:

>

Open question to everybody: What you're opinion on using opCast for this? Since it's a type conversion, it seems fitting to me.

Can't converting without explicitly specifying in D is a big shortcoming in my opinion. There is such a thing as implicitly convertion though, but it's very confusing. I don't see that simplicity in C++ in the D codes!

#include <iostream>
using namespace std;
struct Fraction {
    int num, den;

    Fraction(int n, int d) {
        num = n;
        den = d;
    }

    // Conversion operator: return float value of fraction
    operator float() const
    {
        return float(num) / float(den);
    }
};

int main()
{
    Fraction f(2, 5);
    float val = f;
    cout << val << '\n'; // 0.4
    return 0;
}

You should do the same in D like this:

struct Fraction {
	int num, den;

	this(int n, int d)
	{
		num = n;
		den = d;
	}

	// Cast Expression : convert float value of fraction
	auto opCast(T : float)() const
	{
		return cast(float)(num) / cast(float)(den);
	}
}

import std.stdio;

int main()
{
	auto f = Fraction(2, 5);
	float val = cast(float)f;
	val.writeln; //0.4
	return 0;
}

SDB@79

May 17, 2023

On Friday, 12 May 2023 at 15:00:48 UTC, Salih Dincer wrote:

>
struct Fraction {
	int num, den;

	this(int n, int d)
	{
		num = n;
		den = d;
	}

	// Cast Expression : convert float value of fraction
	auto opCast(T : float)() const
	{
		return cast(float)(num) / cast(float)(den);
	}
}

If you want auto-conversion, you should be more explicit:

float opCast() { }

because if you return "auto" it is not the highest-prio fit and therefore not chosen.
If you have multiple choices, you still don't need to use "auto". Instead you can return T:

T opCast(T)() if(isFloatingPoint!T)
{
   return cast(T)num / cast(T)den; // float, double or real
}

Kind of ironic, but especially "auto" does NOT fit automatically :-)

May 17, 2023

On Wednesday, 17 May 2023 at 08:00:17 UTC, Dom DiSc wrote:

>

If you want auto-conversion, you should be more explicit:

float opCast() { }

because if you return "auto" it is not the highest-prio fit and therefore not chosen.
If you have multiple choices, you still don't need to use "auto". Instead you can return T:

T opCast(T)() if(isFloatingPoint!T)
{
   return cast(T)num / cast(T)den; // float, double or real
}

Kind of ironic, but especially "auto" does NOT fit automatically :-)

Sorry for not expressing myself better. Let me try to explain with another example:

struct RightShift
{
  int num, shr;

  T opCast(T : char)()
   => cast(T)(num >> shr);
}
import std.stdio;
void main()
{
  auto f = RightShift(128, 2);
  char chr = cast(char)f | '\1';
  assert(chr == '!');
  
  //char test = f; // Error: cannot implicitly convert expression
  //assert(test == ' '); // `f` of type `RightShift` to `char`
}

This snippet works fine. But hidden the code gives an error. The reason is that the compiler ignores the explicitly specified lines without using auto.

SDB@79

1 2
Next ›   Last »