Re: length's type.

2024-02-13 Thread Kevin Bailey via Digitalmars-d-learn

On Tuesday, 13 February 2024 at 23:57:12 UTC, Ivan Kazmenko wrote:


I'd like to note that even C++20 onwards has `.ssize`, which is 
signed size.


I do use lengths in arithmetic sometimes, and that leads to 
silent bugs currently.  On the other hand, since going from 16 
bits to 32 and then 64, in my user-side programs, I had a flat 
zero bugs because some length was 2^{31} or greater -- but at 
the same time not 2^{32} or greater.  So, in D, I usually 
`to!int` or `to!long` them anyway.  Or cast in 
performance-critical places.


Another perspective.  Imagine a different perfect world, where 
programmers just had 64-bit integers and 64-bit address space, 
everywhere, from the start.  A clean slate, engineers and 
programmers designing their first hardware and languages, but 
with such sizes already feasible.  Kinda weird, but bear with 
me a bit.  Now, imagine someone proposing to make sizes 
unsigned.  Wouldn't that be a strange thing to do?  The benefit 
of having a universal arithmetic type for everything, from the 
ground up -- instead of two competing types producing bugs at 
glue points -- seems to far outweigh any potential gains.  
Unsigned integers could have their small place, too, for bit 
masks and microoptimizations and whatnot, but why sizes?  The 
few applications that really benefit from sizes of 
[2^{63}..2^{64}) would be the most odd ones, deserving some 
workarounds.


Right now though, we just have to deal with the legacy, in 
software, hardware, and mind -- and with the fact that quite 
some environments are not 64-bit.


Ivan Kazmenko.


Personally, I don't have a problem with .length being unsigned. 
How do you have a negative length? My problem is that the 
language doesn't correctly compare signed and unsigned.


Earlier in the thread, people mentioned NOT mentioning other 
languages but I just learned that Carbon correctly compares 
signed and unsigned ints.


cheers



Re: length's type.

2024-02-09 Thread Kevin Bailey via Digitalmars-d-learn

On Friday, 9 February 2024 at 11:00:09 UTC, thinkunix wrote:


First off I, I am just a beginner with D.  I joined this list 
to try to
learn more about the language not to but heads with experts.  
I'm sorry

if you took my response that way.


Hi thinkunix,

I did interpret your post as critical. Sorry if it wasn't 
intended to be and my reply had a little too much heat. I still 
think my reply was at least accurate, so replies below.


My post was merely to show how, with my rudimentary knowledge, 
I could
get the loop to execute 4 times, which appeared (to me) to be 
the intent of your code.  Thank you for the exercise.  I 
learned more about the D type system.


I said I would not write code like that because:
* why start at -1 if array indexes start at 0?


The program that I was writing was most elegant doing that. 
Obviously I wasn't doing something as simple as the example. The 
post is simply to highlight the issue.


Unfortunately I can't find the examples now. The code has been 
altered so grepping isn't finding it and, since AoC has 25 days, 
I'm not sure which ones it was. It /might/ have been this, where 
'where_to_start' is signed and can be negative. It's a weird 
index of indexes thing, and quite unconventional.


// Try it in the remaining groups.
for (auto i = where_to_start; i < num_ss.length; ++i)

* why use auto which made the type different than what .length 
is?


Google "almost always auto" for why you should prefer it - don't 
miss Herb Sutter's post - but as someone else pointed out, it's 
no better with 'int' *or* 'ulong'.


The "best" solution is to cast the returned length to long. This 
makes it work and, unless you're counting the atoms in the 
universe, should be sufficient on a reasonable machine.


This is why I brought up the example. zjh was lamenting having to 
cast, as am I, much less think this hard about it.


You provided no context, or comment indicated what you were 
trying
to achieve by starting with -1.  Clearly I didn't understand 
your

intent.


I wasn't asking a question. I know how to code this in D and I 
made it work. My post was to highlight the completely unnecessary 
need to cast.


What happens when there's a more reasonable example? What happens 
when you need to compare 2 library function results when one is 
signed and the other not? Would you even know that you had to 
cast one? Or would you just get strange results and not know why? 
The issue exists completely outside of my example.


Since you sound new, I'll mention that, yes, what I'm proposing 
can be a hair slower. But so what? 99 of a 100 programs won't 
notice and, if it does, your profiler will tell you where, you 
add the cast (or you add it ahead time, since that's what we have 
to do now), done.


I understand that it is almost certainly too late for D but the 
world seems ready for an alternative to C++ and lots of languages 
are coming. This is just part of that discussion, right?




Re: length's type.

2024-02-08 Thread Kevin Bailey via Digitalmars-d-learn

Arafel,

You're certainly correct. Priorities change. It used to be 
thought that backwards compatibility was the way to attract 
developers. But today the keyword is "safety".


Apparently 2022 was the year of the C++ successor. Some features 
of D were mentioned in the discussion but D as a candidate was 
not. Maybe it's time to re-visit the priorities.


Anyways, my post was simply to highlight the issue.

On Thursday, 8 February 2024 at 15:26:16 UTC, kdevel wrote:


Elegant and correct is this version:

```d
import std.stdio;

int main()
{
char[] something = ['a', 'b', 'c'];

writeln("len: ", something.length);
writeln("typeid(something.length): ",
typeid(something.length));

writeln ("i: -1");
foreach (i, _; something)
writeln("i: ", i);
return 0;
}
```

But it is still a bit too "clever" in the `foreach` statement 
due to the unused variable `_`.


It has a bigger problem. What happens when I change the code in 
the loop but forget to change the code outside the loop? This is 
why people complain about Python's lack of a do/while loop. So 
no, not elegant.


Additionally, it doesn't address the issue. It still requires me 
to both realize the issue with comparing an int to length's 
mystery type, as well as to fix it for the compiler.


(And it's beside the fact that the start value could just as 
easily be an int (parameter for example) that could take a 
negative value. This was the case for one of my cases.)




Re: length's type.

2024-02-08 Thread Kevin Bailey via Digitalmars-d-learn

On Thursday, 8 February 2024 at 08:23:12 UTC, thinkunix wrote:


I would never write code like this.


By all means, please share with us how you would have written 
that just as elegantly but "correct".


It would also break if the array 'something' had more than 
int.max elements.


Then don't cast it to an int. First of all, why didn't you cast 
it to a long? Second, why doesn't the language do this correctly 
so I don't have to cast it at all? If I explicitly use 
checkedint, it does, but I don't want to write Checked!(int, 
ProperCompare) all over the place. (Yes, I know I can alias it.)


I'm asking, why is the default C compatibility (of all things) 
rather than "safety that I can override if I need to make it 
faster" ?




Re: length's type.

2024-02-07 Thread Kevin Bailey via Digitalmars-d-learn

On Wednesday, 7 February 2024 at 20:13:40 UTC, Gary Chike wrote:

On Wednesday, 7 February 2024 at 20:08:24 UTC, Gary Chike wrote:
On Wednesday, 7 February 2024 at 19:32:56 UTC, Gary Chike 
wrote:



double c = (double)sumArray(a, aLength) / aLength;


If I don't cast explicitly:

`double c = sumArray(a, aLength) / aLength;`

then I will get a similar result as the D code:

`Average: 9223372036854773760.00`


I don't think it's productive to compare the behavior to C. C is 
now 50 years old. One would hope that D has learned a few things 
in that time.


How many times does the following loop print? I ran into this 
twice doing the AoC exercises. It would be nice if it Just Worked.

```
import std.stdio;

int main()
{
  char[] something = ['a', 'b', 'c'];

  for (auto i = -1; i < something.length; ++i)
writeln("less than");

  return 0;
}
```



Re: Changing behavior of associative array

2023-12-16 Thread Kevin Bailey via Digitalmars-d-learn

On Saturday, 16 December 2023 at 22:44:16 UTC, Dennis wrote:


That's because `m[f] = 1` initializes the associative array to 
something non-null. If you pass a `null` AA to a function which 
adds things, the caller will still have a null pointers. You 
can initialize a non-null empty AA like this:


```D
uint[Foo] m = new uint[Foo];
```

Then, `m` can be passed by value and you can make additions or 
removals which the caller sees, unless you assign a new AA in 
the function.


Thanks Dennis. I'll have to tweak my mental model of what's 
happening. I was picturing a std::map-like thing that was passed 
by reference, but instead it seems like 'm' is a pointer to a 
std::map, that is initialized on use if null. (I think it's that 
latter part that gives the illusion of being already initialized.)




Changing behavior of associative array

2023-12-16 Thread Kevin Bailey via Digitalmars-d-learn
Perhaps someone can help solve this mystery. I have a sample 
program that adds structs to an associative array (as keys) in a 
subroutine. The program passes the array by reference as expected 
(below).


My real program does the same thing and yet the associative array 
is passed by value. Thus anything added in the subroutine is lost.


I've added a TON of writeln's to confirm this. The *instant* I 
made the parameter "ref", the real program starts acting as 
expected, and the print-outs show the correct results.


Does anyone know why the behavior would change? Has anyone seen 
anything like this?


I even tried importing the same libraries into both programs. The 
only remaining difference is that the real function has several 
more arguments (7), but I would be shocked if D changed its 
behavior because of that.


thx
```
import std.stdio;

struct Foo
{
uint a, b, c;
}

void add_one_and_recurse(
uint[Foo] m,
int x)
{
if (!x)
return;
foreach (k,v; m) // Prints the 1 from main()
writeln(k, ", ", v); // as expected.
add_one_and_recurse(m, x-1);
Foo f = {4, 5, x};
m[f] = 7;
}

int main()
{
uint[Foo] m;
Foo f = {1, 2, 3};
m[f] = 1;
add_one_and_recurse(m, 3);
foreach (k,v; m) // Prints 4 items
writeln(k, ", ", v); // as expected.
return 0;
}
```



Re: Permutations of array (slice) ?

2023-12-15 Thread Kevin Bailey via Digitalmars-d-learn
On Wednesday, 13 December 2023 at 20:28:11 UTC, Nick Treleaven 
wrote:


This code works for me. (The last 20+ lines are `b`):
```d
import std;
void main() {
char[] as = replicate(['a'], 5);
as[0] = 'b';
foreach (perm; as.byChar.permutations)
writeln(perm);
}
```
Try it on https://run.dlang.io/. Maybe there's some issue on 
your machine?
Also if you use `string as = "abcde";` you can see the 
permutations better.


Revisiting this, I see that it works now. I suspect that I had

writeln(as);

Nevertheless, nextPermutation() does what I really want, which is:

(given as[4] = 'b')

b
aaaba
aabaa
abaaa
b



Re: Permutations of array (slice) ?

2023-12-12 Thread Kevin Bailey via Digitalmars-d-learn

On Tuesday, 12 December 2023 at 15:20:23 UTC, Paul Backus wrote:


Because of autodecoding [1], slices of char and wchar are 
treated by Phobos as bidirectional ranges of dchar. (They are 
not random-access ranges because UTF-8 and UTF-16 are 
variable-length encodings.)


To work around this, use std.utf.byChar:

import std.utf: byChar;
foreach (perm; as.byChar.permutations)
writeln(perm);

[1] 
http://ddili.org/ders/d.en/ranges.html#ix_ranges.decoding,%20automatic


ah, many thanks, I never would have figured that out.

But unfortunately, the code shown now prints 120 lines of:

b

120 being suspiciously equal to 5!. The documentation[2] seems to 
imply that this should be:


b
abaaa
...

When I replace the char[] with int[] [2, 1, 1, 1, 1], it produces 
120 lines of random arrangements of the input, but mostly just 
repeating the input.


Clearly it's doing permutations of a separate array of [0, 1, 2, 
3, 4], and then replacing each index with the element at that 
index (or the equivalent) but it's not even doing that right.


I'll play with nextPermutation. I suspect it would have to be 
implemented the way that I'm expecting.


[2] 
https://dlang.org/library/std/algorithm/iteration/permutations.html





Permutations of array (slice) ?

2023-12-12 Thread Kevin Bailey via Digitalmars-d-learn
Could I get some help with a trivial question, I'm sure? How do 
pass a slice as a range? This code:


import std.algorithm; // permutations
import std.range; // replicate
import std.stdio; // writeln

int main()
{
char[] as = replicate(['a'], 5);
as[0] = 'b';
foreach (perm; as.permutations)
writeln(perm);
}

appears to complain (actual error below) that 'as' is not a range.

Using the slice trick "as[]" from:

https://forum.dlang.org/thread/oxohqaicmpteesugs...@forum.dlang.org

doesn't help either. Something obvious I'm missing, I hope.

perm.d:8:26: error: none of the overloads of template 
‘std.algorithm.iteration.permutations’ are callable using 
argument types ‘!()(char[])’

8 | foreach (perm; as.permutations)
  |  ^
/usr/lib/gcc/x86_64-linux-gnu/13/include/d/std/algorithm/iteration.d:7919:20: 
note: Candidate is: ‘permutations(Range)(Range r)’
 with `Range = char[]`
  must satisfy the following constraint:
`   isRandomAccessRange!Range`
 7919 | Permutations!Range permutations(Range)(Range r)
  |^



Re: Find in assoc array then iterate

2022-10-22 Thread Kevin Bailey via Digitalmars-d-learn
ah, I knew that I could iterate over byKey, but I didn't know 
that it was a
tangible thing, that you could hold in your hand. This should be 
fine, and

I'll use your template trick for passing it to a function.

Thanks Paul and Ali!



Re: Find in assoc array then iterate

2022-10-22 Thread Kevin Bailey via Digitalmars-d-learn

Siarhei,

Thanks for this possibility. I didn't know D had "pointers" like 
this.
Unfortunately, it appears that you can't pick up where you left 
off with

that pointer? You have to re-scan forward?

bachmeier,

I didn't reply to Steven's question; I replied to his claim that 
there
was no value. I found his response insulting and patronizing, and 
has
no place on a public forum helping evangelize D. See Siarhei's 
response

for a better way.

Siarhei,

I'm attempting to do something like a DFS down a fixed list of 
strings.
It's doing something like generating permutations of the strings, 
however
the conditions for the search are fairly complicated, and of 
course I'm
trying to do as much "early exit" as possible. That is, I can 
prune

branches just seeing the first or second word.

IOW, if D could, for example, "iterate through all 3 word 
combinations
in this list", it would be useless to this problem (or at least 
*very*
expensive.) OTOH, a forward iterator (i.e. copyable but does not 
need to

go backwards) solves the problem elegantly and efficiently.

Go-lang supports it too:

package main

import "fmt"
import "reflect"

func main() {
m := make(map[string]int)
m["key1"] = 7
m["key2"] = 8
iter := reflect.ValueOf(m).MapRange()
// Advance iterator
iter.Next()
// Preserve position
iter2 := *iter
// Exhaust first iterator
for iter.Next() {
fmt.Println("iter: ", iter.Key())
}
// What does second iterator see?
for iter2.Next() {
fmt.Println("iter2: ", iter2.Key())
}
}

will correctly print:

iter: key2
iter2: key2



Re: Find in assoc array then iterate

2022-10-21 Thread Kevin Bailey via Digitalmars-d-learn

Hi Sergey,

While the unordered map doesn't guarantee an ordering (since its 
contents are
hashed), the order should remain static if you don't insert or 
delete.


Hi JG,

Thanks for the red-black tree reference. I'll read up on it in 
case I need it

but I'd prefer to use the built-in O(1) hash map.

Hi again Ali!,

I did consider a sort, but it has a number of downsides:
- it's O(n ln(n))
- if I'm understanding correctly, it would require additional 
memory
- Not relevant to my problem but, if you had duplicates, it 
wouldn't handle
stopping in the middle of some duplicates and re-starting; only 
iterators

support this.

One could more easily copy the keys into an array, and iterate on 
them.


Thus, I was hoping to find a member function that would support 
this.


Steven,

Just because you don't see the value doesn't mean I don't. You 
should try to

be more helpful, or don't bother.



Find in assoc array then iterate

2022-10-21 Thread Kevin Bailey via Digitalmars-d-learn

I'm trying to do this equivalent C++:

unordered_map map;

for (auto i = map.find(something); i != map.end(); ++i)
...do something with i...

in D, but obviously with an associative array. It seems that it's 
quite
easy to iterate through the whole "map", but not start from the 
middle.

Am I missing something obvious (or not so obvious) ?



Re: Why are structs and classes so different?

2022-05-17 Thread Kevin Bailey via Digitalmars-d-learn

Hi again Ali!

On Monday, 16 May 2022 at 21:58:09 UTC, Ali Çehreli wrote:


I for one misunderstood you. I really thought you were arguing 
that struct and class should be the same.


To be specific:
- My *primary* concern is that:

Foo foo;

is undefined behavior waiting to happen, that I can't detect at a 
glance.


- A *secondary* goal would be for class objects to be able to 
have deterministic destructors like structs.


The first looks trivial: Just have it allocate a Foo by default.

The second looks like it could have been designed that way, 
albeit with other minor changes to the language, and, I was 
curious why it wasn't.


C++ is proof that it can indeed work the other way. However, 
for it to work correctly, programmers must follow guidelines. 
Here are four:


But again, from this discussion, it seems D could have simply had 
pass-by-reference for class objects, preserving everything D 
strives for, but by-value stack initialization, providing what 
people expect from stack objects. There's no need to drag C++ 
design into it.


C++ does not use terms "value type" and "reference type" to 
make any distinction but the rules above are proof enough for 
me that C++ implicitly divides user-defined types into such 
categories.


I would beg to differ here. In C++, all types are value types, 
until you add punctuation. This is one of the things that I like 
about C++, that I trip over in other languages. e.g. In Rust, 
there are 2 similar types, is it int and float, where one is 
copyable and the other move-only? How can you write generic code 
in that environment?


Yes, in C++, you have to worry about slicing and copying 
singletons, but these are problems in front of you. It's the 
problems that sneak up behind you that I worry about.


Ok, I think I see better now. You would like members of a class 
recursively placed next to each other in memory. What if a 
polymorphic type had a polymorphic member?


You mean like a string? I don't have a problem with this:

class MyString {
   uint length;
   ...pointer to data...
}

void func() {
   MyString s;
   if (s.length == 0)  // I want this to be perfectly safe.
  writeln("empty");
   // 's' destroyed here, could do something useful
}

In D, some objects can do this; some can't!

I don't understand that example. I see a programmer error of 
casting a Foo to a Bar.


Correct, I was responding to a comment. I was pointing out that 
the only "slicing" that we need to worry about with by-reference 
is if we are already doing something wrong, and that D won't help 
you there.


Did you mean C#? C# is like D: structs are value types and 
classes are reference types.


You missed the part where I said, "ignoring structs". :-)

With all due respect, based on other conversation here, may I 
assume you those projects were based on C++? If you also had 
any language with reference types like Python, did you have the 
similar issues with those languages?


Python is a toy language, right? I'm not aware of any large 
projects in it. (The largest I worked with was 138 files, 31k 
lines - tiny.)


Java would be a better comparison, but it has auto-closable 
objects, unlike D and Python. Perhaps it has succeeded because 
there are so few types that *aren't* by reference. Perhaps one 
just gets used to it. (I've written Android apps, but I would 
never write a long-running service in it.)


This is unfortunate for D where you have to keep track.

I accepted D's struct/class separation since the beginning and 
never had any issue with it. It just worked for me.


Perhaps you are familiar with the types that you work with on a 
daily basis. Perhaps the project is small. Perhaps your IDE 
colors classes brightly. I don't know, but an anecdote doesn't 
mean much compared to the fact that nearly all large projects are 
in C++, and I don't mean "due to inertia." I mean, "and they're 
successful."




Re: Why are structs and classes so different?

2022-05-16 Thread Kevin Bailey via Digitalmars-d-learn

On Monday, 16 May 2022 at 19:06:01 UTC, Alain De Vos wrote:

A new syntax like "*" should introduce something new.
If it's not needed for classes why introduce it.


Hi Alain!

I have to sympathize with Johan. If you see:

Foo foo = get_foo();
call_function(foo);

can 'foo' change in 'call_function()' ? Is it by-reference or is 
it by value?


Foo* foo = get_foo();

How about now? Pretty obvious.

call_function();

Also obvious.

To re-phrase your claim, a new syntax doesn't need to introduce 
something new. Syntax is there to convey information.



If you don't know if something is a class name it class_blabla.
Just remember the effect of "="


ah, I see the problem. You've never worked in a large code-base 
written by thousands of other people. I do every day. I can't 
make them name things in any special way. But when I see the 
above code, I need to know exactly what it does with just a scan.




Re: Why are structs and classes so different?

2022-05-16 Thread Kevin Bailey via Digitalmars-d-learn

Great responses, everyone. I'll try to address all of them.

Mike, I know the rules. I was asking, "Why is it this way? Why 
was it designed this way? What bad thing happens the other way?" 
When I think about most things in D, I can at least think of a 
reason, even if I don't agree with it. But not putting class 
objects on the stack makes no sense to me (assuming we still pass 
by reference.) Reasons below.


Ola, your response is very interesting. I would say that 
assignment isn't any more or less of an issue, as long as you 
pass by reference:


// Using C syntax to make intent clear.
class Foo { int x; }
class Bar: Foo { int y; }

void func1(Bar* bar) {
  bar.y = 4; // boom
}

void func2(Bar* bar) {
  Foo* foo = bar;
  foo.x = 3; // this is fine

  foo = new Foo;
  func1(cast(Bar*)(foo)); // uh oh
}

Illuminating comment about the ABI.

Ali, I've never liked the distinction between 'struct' and 
'class' in C++ either, but that's no reason to actually make them 
different. It's a reason to remove 'class' and save the keyword.


re: pass-by-reference and performance, agreed, this is why we 
pass integers in registers. But a struct on the stack is just as 
fast to access locally through a pointer register - "[bp+6]" - as 
remotely, yes?


Finally, 'scope' is nice but it doesn't solve the segfault issue.

HS Teoh: See above for my responses about assignment and 'scope'.

bauss: "But that's not entirely true as you can allocate a struct 
on the heap as well."


forkit: "where they live in memory should be less of the 
programmers concern, and more an implementation issue (although 
some programmers will of course consider this as well)."


Precisely. You can allocate structs, and you can put class 
objects in 'scope' variables. (I'm not sure if this was your 
intent, forkit, but) a class object can live on the stack just as 
easily as on the heap, as long as you pass by reference. The only 
danger is if a called function tries to own a stack allocated 
object, but this is a concern for heap allocated objects too. 
This is why C++ has moveable types and unique_ptr.


Walter, Thanks for the insightful reply! I'm getting the sense 
that the decision was made in order to make the language simpler. 
That is, ignoring struct's, D went the Java path: You can have 
any color you like, as long as it's grey.


I agree that C++'s organic growth allows programmers to do things 
they shouldn't, and requires that they be more careful. But I 
would not have gone from there to Java.


I think an interesting middle-ground would be a language that had 
"template" types - Copyable, MoveOnly, Interface, Singleton, 
FactoryBuilt, etc. I've learned from all the projects that I've 
been on that we need all these types. We can either ask 
programmers to hand-craft them, or we can provide them. Note that 
in C++, we can get pretty close:


class Foo: Moveable { ...

And then there's the segfault issue. I think that, if we're going 
to ignore a huge problem like that, there has to be very strong 
reasons. From this discussion, it doesn't sound like they were 
very strong.


Of course, it's done and there's little changing it. A seemingly 
harmless fix would be to not require 'new':


Foo foo; // this allocates an object
Foo foo = null; // this does not
Foo foo = function(); // this doesn't either

In fact, I suspect we could make that change today and few would 
notice. Nevertheless, I'm still a little shocked that this isn't 
existing behavior.


cheers all



Re: Why are structs and classes so different?

2022-05-15 Thread Kevin Bailey via Digitalmars-d-learn

Hi Mike (and Guillaume, since you posted the same link),

Thanks for the long explanation.

I've been programming in C++ full time for 32 years, so I'm 
familiar with slicing. It doesn't look to me like there's a 
concern here.


There seem to be a couple different questions here. I suspect 
that you answered a different one than I asked.


One question is, how should we pass objects - by value or by 
reference? In C++, you can do either, of course, but you take 
your chances if you pass by value - both in safety AND 
PERFORMANCE. The bottom line is that no one passes by value, even 
for PODs (although we may return even large objects.)


But I asked a different question: Why can't I put a class object 
on the stack? What's the danger?


Note that operating on that object hasn't changed. If I pass by 
reference, it's no different than if I had created a reference.


One might say, Well, if D creates by value, then it has to pass 
by value. But it doesn't; it has the 'ref' keyword.


One might want to avoid passing by value accidentally. Ok, one 
could have D pass class objects by reference implicitly.


I don't like things silently changing like that, so one might 
have D forbid all but pass by 'ref' or pointer for class objects.


In any case, this doesn't quite address the instantiate by value 
issue.


If there's still a case where putting an object on the stack 
breaks, I would greatly appreciate seeing a few lines of example 
code.


I hope Ali's answer isn't the real reason. I would be sad if D 
risked seg faults just to make class behavior "consistent".


thx



Why are structs and classes so different?

2022-05-15 Thread Kevin Bailey via Digitalmars-d-learn
I've done some scripting in D over the years but I never dug into 
D until recently. I'm going through Learning D and I was reminded 
that structs and classes are so different.


- struct methods are non-virtual while class methods are virtual
- Thus, structs can't inherit, because how would you find the 
child's destructor given a parent pointer?

- On the stack, structs by-value but classes are by-reference

I'm trying to understand why it is this way. I assume that 
there's some benefit for designing it this way. I'm hoping that 
it's not simply accidental, historical or easier for the compiler 
writer.


One problem that this causes is that I have to remember different 
rules when using them. This creates the additional load of 
learning and remembering which types are which from someone 
else's library.


A bigger problem is that, if I have a struct that I suddenly want 
to inherit from, I have to change all my code. In addition to 
that work, in both of these cases, one could easily do it wrong:


// Fine with a struct, fatal with a class.
Foo foo;

At least in C++, the compiler would complain. In D, not even a 
warning.


Why is it this way? What is the harm of putting a class object on 
the stack?




Template arg deduction

2021-07-07 Thread Kevin Bailey via Digitalmars-d-learn
I'm trying to use some fairly simple template argument deduction, 
but
maybe I'm not getting the syntax correct. C++ doesn't event blink 
at

something like this, but D is giving me:

temptest.d(18): Error: template temptest.func cannot deduce 
function from argument types !()(bar), candidates are:

temptest.d(10):func(T)(foo!T.bar f)

I guess D can't crack open a type like that?

```
template foo(T)
{
class bar
{
T t;
}

}

void func(T)(// 10
foo!(T).bar f)
{
}

int main()
{
foo!int.bar fi;
func(fi);// 18
}
```



Re: Trying to search a range

2021-07-02 Thread Kevin Bailey via Digitalmars-d-learn

On Saturday, 3 July 2021 at 01:15:20 UTC, Paul Backus wrote:


The error message here is actually telling you exactly what the 
problem is: `findSplit` requires a forward range, but the range 
returned by `File.byLine` is not a forward range, just an input 
range.




Hey Paul,

Thanks for the pointer. I doubt I would have figured out that
surprising detail. Nevertheless, now I know where to look for
the exact error. :-)



Trying to search a range

2021-07-02 Thread Kevin Bailey via Digitalmars-d-learn
Sorry if this is too simple of a question, but I'm trying to 
simply find

a blank line in a file. I'm doing something like:

```
auto file = File("somefile");
auto r = file.byLine();
auto tup = r.findSplit("");
// tup[0] would contain the range before the line,
// tup[2] would contain the range after, not unlike findSplit
```

Unfortunately, ldc2 is saying:

```
split.d(8): Error: template std.algorithm.searching.findSplit 
cannot deduce function from argument types !()(ByLineImpl!(char, 
char), string), candidates are:

/usr/lib/ldc/x86_64-linux-gnu/include/d/std/algorithm/searching.d(2882):
findSplit(alias pred = "a == b", R1, R2)(R1 haystack, R2 needle)
  with pred = "a == b",
   R1 = ByLineImpl!(char, char),
   R2 = string
  must satisfy the following constraint:
   isForwardRange!R1
```

I can't tell if findSplit() only works on strings, or if maybe I'm
trying to compare different types of strings, or if I'm overtaxing
the type deduction system.




q about slices, strings

2019-07-13 Thread Kevin Bailey via Digitalmars-d-learn
I saw on the dlang.org homepage a sample of code that looks a 
little strange to me:


int[char[2]] aa;
auto arr = "ABBBA";

foreach (i; 0 .. arr.length - 1)
aa[arr[i .. $][0 .. 2]]++;

which I changed to:

aa[arr[i .. i+2][0 .. 2]]++;

in the hopes of only doing:

aa[arr[i .. i+2]]++;

The question is: Why is the [0..2] still necessary?

Without it, dmd (on that homepage) complains:

 cannot implicitly convert expression arr[i..i + 2LU] of type 
string to char[2]


The spec says that:

10.22 Slices
...
6. If the slice bounds can be known at compile time, the slice 
expression is implicitly convertible to an lvalue of static array.


7. The following forms of slice expression can be convertible to 
a static array type:


e An expression that contains no side effects.
a, b  Integers (that may be constant-folded).

Form   The length calculated at compile time
...
arr[e .. e+b]  b

So why isn't arr[i .. i+2] convertible? Is dmd behind the spec 
here?