www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Completing C code with D style

reply pascal111 <judas.the.messiah.111 gmail.com> writes:
Next code originally was a classic C code I've written, it's pure 
vertical thinking, now, I converted it successfully to D code, 
but I think I made no much changes to make it has more horizontal 
thinking style that it seems D programmers care in horizontal 
thinking style. Is there any additions I can make in the code to 
make it suitable with D style or it's fine?

// D programming language

import std.stdio;

int main()
{


     int numbers[10]=[-3, 14, 47, -49, -30, 15, 4, -82, 99, 26];
     char negativity,
           even;

write("Would you like in list (n=negatives, p=positives, b=both)? 
");
readf(" %c", &negativity);


write("Would you like in list (e=evens, o=odds, b=both)? ");
readf(" %c", &even);


     for(int i=0; i<10; ++i)
     	{
     	 if(negativity=='n')
     	 	{
     	 	if(numbers[i]>0)
     	 		continue;
     	 	}
     	 else{
     	  if(negativity=='p')
     	  	if(numbers[i]<0)
     	  		continue;
     	  }
     	
     	  if(even=='e')
     	 	{
     	 	if(numbers[i]%2)
     	 		continue;
     	 	}
     	 else{
     	  if(even=='o')
     	  	if(!(numbers[i]%2))
     	  		continue;
     	  }		
     	 writefln("%d",numbers[i]);
     	}
     	
     	
     return 0;
     }
Nov 02 2021
next sibling parent reply Siarhei Siamashka <siarhei.siamashka gmail.com> writes:
On Tuesday, 2 November 2021 at 23:45:39 UTC, pascal111 wrote:
 Next code originally was a classic C code I've written, it's 
 pure vertical thinking, now, I converted it successfully to D 
 code, but I think I made no much changes to make it has more 
 horizontal thinking style that it seems D programmers care in 
 horizontal thinking style. Is there any additions I can make in 
 the code to make it suitable with D style or it's fine?
By "vertical" vs. "horizontal" thinking, do you mean imperative vs. functional style? https://en.wikipedia.org/wiki/Functional_programming#Imperative_vs._functional_programming It's supported in many modern programming languages and it's not a unique feature of the D language alone. Your code can be changed to something like this: import std.stdio, std.algorithm, std.conv, std.string; void main() { auto numbers = [-3, 14, 47, -49, -30, 15, 4, -82, 99, 26]; char negativity, even; write("Would you like in list (n=negatives, p=positives, b=both)? "); readf(" %c", &negativity); write("Would you like in list (e=evens, o=odds, b=both)? "); readf(" %c", &even); numbers.filter!(x => !((negativity == 'n' && x > 0) || (negativity == 'p' && x < 0))) .filter!(x => !((even == 'e' && (x % 2)) || (even == 'o' && !(x % 2)))) .map!text.join("\n").writeln; }
Nov 02 2021
next sibling parent pascal111 <judas.the.messiah.111 gmail.com> writes:
On Wednesday, 3 November 2021 at 00:50:51 UTC, Siarhei Siamashka 
wrote:
 On Tuesday, 2 November 2021 at 23:45:39 UTC, pascal111 wrote:
 It's supported in many modern programming languages and it's 
 not a unique feature of the D language alone. Your code can be 
 changed to something like this:

     import std.stdio, std.algorithm, std.conv, std.string;

     void main()
     {
       auto numbers = [-3, 14, 47, -49, -30, 15, 4, -82, 99, 26];
       char negativity, even;

       write("Would you like in list (n=negatives, p=positives, 
 b=both)? ");
       readf(" %c", &negativity);

       write("Would you like in list (e=evens, o=odds, b=both)? 
 ");
       readf(" %c", &even);

       numbers.filter!(x => !((negativity == 'n' && x > 0) ||
                              (negativity == 'p' && x < 0)))
              .filter!(x => !((even == 'e' && (x % 2)) ||
                              (even == 'o' && !(x % 2))))
              .map!text.join("\n").writeln;
     }
Wow! your code seem so nice, I like it although I don't know how exactly it works. For now I'll keep learning traditional imperative programming style then after that I'll look in the functional one, it's new to me.
Nov 02 2021
prev sibling next sibling parent reply =?UTF-8?Q?Ali_=c3=87ehreli?= <acehreli yahoo.com> writes:
On 11/2/21 5:50 PM, Siarhei Siamashka wrote:
 Your code can be changed to 
 something like this:
And I over-engineered it. :) import std.stdio; import std.algorithm; import std.range; import std.exception; import std.format; // A readable name; corresponds to C's typedef alias FilterFunction = bool function(int); // These are our filters; they will be initialized not right // where they are defined but in a following 'shared static // this()'. (This is a current D implementation issue.) immutable FilterFunction[string] negativityFilters; immutable FilterFunction[string] evennessFilters; // 'shared static this()' blocks are executed before main() // is executed. shared static this() { const matchAll = (int _) { return true; }; negativityFilters = [ "negatives" : (int i) { return i <= 0; }, "positives" : (int i) { return i >= 0; }, "both" : matchAll, ]; evennessFilters = [ "evens" : (int i) { return (i % 2) == 0; }, "odds" : (int i) { return (i % 2) == 1; }, "both" : matchAll, ]; } // Picks the filter that corresponds to user input FilterFunction pickFilter(const(FilterFunction[string]) filters) { // The full names of filters e.g. [ "evens", "odds", "both" ] auto fulls = filters.byKey.array.sort; // The first letters of the names e.g. [ 'b', 'e', 'o' ] auto shorts = fulls.map!(key => key.front); // A mapping from short to full name e.g. 'b' -> "both" auto shortToFull = assocArray(shorts, fulls); // Prompt the user by combining the short and full names writef!"Would you like in list (%-(%s, %))? "( zip(shorts, fulls).map!(z => format!"%s=%s"(z[0], z[1]))); char c; readf(" %c", &c); enforce(c in shortToFull, format!"'%s' is not a valid option"(c)); const full = shortToFull[c]; return filters[full]; } // Picks filters according to user input FilterFunction[] pickFilters() { return [ negativityFilters, evennessFilters ].map!pickFilter.array; } // The main logic of the program void run() { auto numbers = [ -3, 14, 47, -49, -30, 15, 4, -82, 99, 26 ]; auto filters = pickFilters(); auto selection = numbers.filter!(n => filters.all!(f => f(n))); writefln!"%-(%s\n%)"(selection); } int main() { try { run(); return 0; } catch (Exception e) { stderr.writefln!"ERROR: %s"(e.msg); return 1; } } Ali
Nov 02 2021
parent pascal111 <judas.the.messiah.111 gmail.com> writes:
On Wednesday, 3 November 2021 at 00:57:38 UTC, Ali Çehreli wrote:
 On 11/2/21 5:50 PM, Siarhei Siamashka wrote:
 Your code can be changed to something like this:
And I over-engineered it. :) import std.stdio; import std.algorithm; import std.range; import std.exception; import std.format;
. . .
 Ali
I think I costed you much efforts. Thank you, it's a great version.
Nov 02 2021
prev sibling next sibling parent pascal111 <judas.the.messiah.111 gmail.com> writes:
On Wednesday, 3 November 2021 at 00:50:51 UTC, Siarhei Siamashka 
wrote:
 On Tuesday, 2 November 2021 at 23:45:39 UTC, pascal111 wrote:
 By "vertical" vs. "horizontal" thinking, do you mean imperative 
 vs. functional style?
 https://en.wikipedia.org/wiki/Functional_programming#Imperative_vs._functional_programming
Maybe you are right, I think that, but I don't know the exact English terms.
Nov 02 2021
prev sibling parent reply Stanislav Blinov <stanislav.blinov gmail.com> writes:
On Wednesday, 3 November 2021 at 00:50:51 UTC, Siarhei Siamashka 
wrote:

     !text.join("\n").writeln;
Ahem... You've turned a program that does not allocate to a program that allocates who knows how much memory? And Ali... associative arrays? For this? What are you trying to teach the good beginner here? :D ```d import std.stdio, std.algorithm; void main() { auto numbers = [-3, 14, 47, -49, -30, 15, 4, -82, 99, 26]; char negativity, even; write("Would you like in list (n=negatives, p=positives, b=both)? "); readf(" %c", &negativity); write("Would you like in list (e=evens, o=odds, b=both)? "); readf(" %c", &even); if ((negativity == 'b') && (even == 'b')) { // don't do any unnecessary work numbers.each!writeln; } else { numbers.filter!(x => !((negativity == 'n' && x > 0) || (negativity == 'p' && x < 0))) .filter!(x => !((even == 'e' && (x % 2)) || (even == 'o' && !(x % 2)))) .each!writeln; } } ```
Nov 03 2021
next sibling parent reply russhy <russhy gmail.com> writes:
The code "as is" is perfectly fine

I don't understand why you guys offer OP such complicate/bloated 
examples, it'll only make things confusing and slow down 
compilation time with templates and imports, this is not needed 
at all


One change, use .length property instead of the hardcoded value

Keeping things simple helps debugging!

```D
int main() {

   int numbers[10] = [-3, 14, 47, -49, -30, 15, 4, -82, 99, 26];
   char negativity, even;
   write("Would you like in list (n=negatives, p=positives, 
b=both)? ");
   readf(" %c", & negativity);

   write("Would you like in list (e=evens, o=odds, b=both)? ");
   readf(" %c", & even);

   // you can access .length property of 
slices/arrays/static_arrays in D
   for (int i = 0; i < numbers.length; ++i) {
     if (negativity == 'n') {
       if (numbers[i] > 0)
         continue;
     } else {
       if (negativity == 'p')
         if (numbers[i] < 0)
           continue;
     }

     if (even == 'e') {
       if (numbers[i] % 2)
         continue;
     } else {
       if (even == 'o')
         if (!(numbers[i] % 2))
           continue;
     }
     writefln("%d", numbers[i]);
   }

   return 0;
}
```
Nov 03 2021
next sibling parent Salih Dincer <salihdb hotmail.com> writes:
On Wednesday, 3 November 2021 at 20:36:08 UTC, russhy wrote:

 I don't understand why you guys offer OP such 
 complicate/bloated examples, it'll only make things confusing 
 and slow down compilation time with templates and imports, this 
 is not needed at all
I don't like complicated things either. Additional facilities are interminable in D :) For example: ```d import std.stdio, std.algorithm, std.array; int main() { auto numbers = [-3, 14, 47, -49, -30, 15, 4, -82, 99, 26]; char negativity, even; Start: bool error; enum sign { negatives = 'n', positives = 'p', both = 'b' } write("Would you like in list (n=negatives, p=positives, b=both)? "); readf(" %c", &negativity); switch (negativity) with(sign) { case negatives: numbers = filter!("a < 0")(numbers).array; break; case positives: numbers = filter!("a > 0")(numbers).array; break; case both: break; default: error = true; goto Error; } enum type { evens = 'e', odds = 'o', both = 'b' } write("Would you like in list (e=evens, o=odds, b=both)? "); readf(" %c", &even); switch (even) with(type) { case evens: numbers = filter!("!(a % 2)")(numbers).array; break; case odds: numbers = filter!("a & 1")(numbers).array; break; case both: break; default: error = true; } Error: if(error) { "Error...".writeln; goto Start; } else writef("%(%s\n%)", numbers); return 0; } ``` Please try to use auto...
Nov 03 2021
prev sibling parent reply jfondren <julian.fondren gmail.com> writes:
On Wednesday, 3 November 2021 at 20:36:08 UTC, russhy wrote:
 Keeping things simple helps debugging!
I'd still have to run your program to be sure of its simple logic, though. The real star d feature that would help with debugging is unittest: ```d enum sign { negatives = 'n', positives = 'p', both = 'b' } enum parity { evens = 'e', odds = 'o', both = 'b' } bool simple(int n, sign s, parity p) { if (n < 0 && s == sign.positives) return false; if (n > 0 && s == sign.negatives) return false; if (n & 1) { if (p == parity.evens) return false; } else { if (p == parity.odds) return false; } return true; } unittest { import std.algorithm : filter, equal; auto numbers = [-3, 14, 47, -49, -30, 15, 4, -82, 99, 26]; alias match = (ns, s, p) => ns.equal(numbers.filter!(n => simple(n, s, p))); assert(match(numbers, sign.both, parity.both)); assert(match([-3, -49], sign.negatives, parity.odds)); assert(match([-30, -82], sign.negatives, parity.evens)); assert(match([14, 4, 26], sign.positives, parity.evens)); assert(match([47, 15, 99], sign.positives, parity.odds)); assert(match([-3, -49, -30, -82], sign.negatives, parity.both)); assert(match([14, -30, 4, -82, 26], sign.both, parity.evens)); } ```
Nov 03 2021
parent reply kdevel <kdevel vogtner.de> writes:
On Thursday, 4 November 2021 at 00:53:11 UTC, jfondren wrote:
 On Wednesday, 3 November 2021 at 20:36:08 UTC, russhy wrote:
 Keeping things simple helps debugging!
I'd still have to run your program to be sure of its simple logic, though. The real star d feature that would help with debugging is unittest:
What about the number 0 (zero)? If 0 is considered to be excluded from the domain how would one define in D a type which cannot represent 0 in the first place? Follow-up question: Are there language facilities such that one could initialize an array of these non-zero-ints like?: ``` nzint [] numbers = [ -2, -1, 1, 2 ]; ``` If 0 is included in the domain the classification of the values into negative and positive ones is not complete since 0 is neither. ``` enum sign { negatives = 'n', positives = 'p', both = 'b' } enum parity { evens = 'e', odds = 'o', both = 'b' } bool simple(int n, sign s, parity p) { if (n < 0 && s == sign.positives) return false; if (n > 0 && s == sign.negatives) return false; if (n & 1) { if (p == parity.evens) return false; } else { if (p == parity.odds) return false; } return true; } unittest { import std.algorithm : filter, equal; version (have_zero) { auto numbers = [-2, -1, 0, 1, 2]; } else { auto numbers = [-2, -1, 1, 2]; } alias match = (ns, s, p) => ns.equal(numbers.filter!(n => simple(n, s, p))); assert(match(numbers, sign.both, parity.both)); assert(match([-1], sign.negatives, parity.odds)); assert(match([-2], sign.negatives, parity.evens)); // fails when we have_zero assert(match([2], sign.positives, parity.evens)); assert(match([1], sign.positives, parity.odds)); assert(match([-2, -1], sign.negatives, parity.both)); assert(match([-2, 2], sign.both, parity.evens)); } ``` ```shell $ dmd -version=have_zero -checkaction=context -unittest -main -run a.d a.d(27): [unittest] false != true 1/1 modules FAILED unittests ```
Nov 06 2021
parent reply jfondren <julian.fondren gmail.com> writes:
On Saturday, 6 November 2021 at 13:27:55 UTC, kdevel wrote:
 On Thursday, 4 November 2021 at 00:53:11 UTC, jfondren wrote:
 On Wednesday, 3 November 2021 at 20:36:08 UTC, russhy wrote:
 Keeping things simple helps debugging!
I'd still have to run your program to be sure of its simple logic, though. The real star d feature that would help with debugging is unittest:
What about the number 0 (zero)?
Not treating it as positive is a bug that I introduced in a rewrite.
 If 0 is considered to be excluded from the domain how would one 
 define in D a type which cannot represent 0 in the first place? 
 Follow-up question: Are there language facilities such that one 
 could initialize an array of these non-zero-ints like?:

 ```
    nzint [] numbers = [ -2, -1, 1, 2 ];
 ```
In general, you use a constructor that tests for non-zero and you take care to maintain the invariant. D has some tools (like invariant) to help with that, but it's not a dependent-typed language. For this specific example, you can sort of do that with std.typecons.Nullable ```d unittest { import std.typecons : Nullable, nullable; import std.algorithm : map; import std.array : array; alias NonZero(T) = Nullable!(T, 0); NonZero!int[] numbers = [-2, -1, 0, 1, 2].map!(i => NonZero!int(i)).array; int sum; int invalids; foreach (n; numbers) { if (n.isNull) invalids++; else sum += n.get; } assert(sum == 0); assert(invalids == 1); } ```
Nov 06 2021
parent kdevel <kdevel vogtner.de> writes:
On Saturday, 6 November 2021 at 13:48:59 UTC, jfondren wrote:
 On Saturday, 6 November 2021 at 13:27:55 UTC, kdevel wrote:
 On Thursday, 4 November 2021 at 00:53:11 UTC, jfondren wrote:
 On Wednesday, 3 November 2021 at 20:36:08 UTC, russhy wrote:
 Keeping things simple helps debugging!
As simple as possible, but not simpler! [...]
 What about the number 0 (zero)?
Not treating it as positive is a bug that I introduced in a rewrite.
Mathematically a whole number (integer) is positive iff it is greater than 0. Since 0 is not greater than 0 0 is not positive. The vocabulary of the program shall be changed such that the term "positive" is replaced with "non-negative". Or one introduces one (0) or two (-0, +0) new signs ...
Nov 06 2021
prev sibling parent =?UTF-8?Q?Ali_=c3=87ehreli?= <acehreli yahoo.com> writes:
On 11/3/21 11:41 AM, Stanislav Blinov wrote:

 And Ali... associative arrays? For this? What are you trying to teach
 the good beginner here? :D
Obviously, we're all enjoying this thread but once the OP made it clear that they wanted a C-like solution, I took some liberty with alternative solutions. :) I think even in production code I would implement something similar at least to keep selection characters like 'n' together with their long forms like "negative". I might use linear searching instead of an assoiative array (or store the assoiative arrays for later use, which I did think about before posting it). But, considering they are generated when interacting with stdin, likely fed by a human, the time loss there is zero. :) Ali
Nov 03 2021
prev sibling next sibling parent reply forkit <forkit gmail.com> writes:
On Tuesday, 2 November 2021 at 23:45:39 UTC, pascal111 wrote:
 Next code originally was a classic C code I've written, it's 
 pure vertical thinking, now, I converted it successfully to D 
 code, but I think I made no much changes to make it has more 
 horizontal thinking style that it seems D programmers care in 
 horizontal thinking style. Is there any additions I can make in 
 the code to make it suitable with D style or it's fine?
Oh man! some of those answers... whoooooohah.... Here's mine, with a little of that horizontal thinking ;-) // ============================================= module test; import std.stdio : write, writeln, writefln, readf; import std.algorithm : filter, sort; import std.array: array; void main() { // NOTE: 0 is neither positive or negative, but is considered to be even int[] numbers = [-3, 14, 47, -49, -30, 15, 4, -82, 99, 26, 0]; int[] result; char answer1; write("Would you like in list (n=negatives, p=positives, b=both)? "); readf(" %c", answer1); debug { writeln("You selected ", answer1); } switch(answer1) { case 'n' : result = numbers.filter!(a => (a < 0)).array; break; case 'p' : result = numbers.filter!(a => (a > 0)).array; break; case 'b' : result = numbers; break; default : writefln("Invalid answer." ); throw new Exception("Bad input!!"); // don't waste my time! } char answer2; write("Would you like in list (e=evens, o=odds, b=both)? "); readf(" %c", answer2); debug { writeln("You selected ", answer2); } switch(answer2) { case 'e' : result = result.filter!(a => (a % 2 == 0)).array; break; case 'o' : result = result.filter!(a => (a % 2 == 1)).array; break; case 'b' : break; default : writefln("Invalid answer." ); throw new Exception("Bad input!!"); // don't waste my time! } writeln(result.sort()); } // =============================================
Nov 08 2021
next sibling parent forkit <forkit gmail.com> writes:
On Monday, 8 November 2021 at 12:04:26 UTC, forkit wrote:
         case 'o' :
             result = result.filter!(a => (a % 2 == 1)).array;
oops. case 'o' : result = result.filter!(a => (a % 2 != 0)).array;
Nov 08 2021
prev sibling parent reply forkit <forkit gmail.com> writes:
On Monday, 8 November 2021 at 12:04:26 UTC, forkit wrote:
 On Tuesday, 2 November 2021 at 23:45:39 UTC, pascal111 wrote:
 Next code originally was a classic C code I've written, it's 
 pure vertical thinking, now, I converted it successfully to D 
 code, but I think I made no much changes to make it has more 
 horizontal thinking style that it seems D programmers care in 
 horizontal thinking style. Is there any additions I can make 
 in the code to make it suitable with D style or it's fine?
Oh man! some of those answers... whoooooohah.... Here's mine, with a little of that horizontal thinking ;-) ....
And just had a little fun transposing my D code back into C. They both produce exactly the same output. But I tell ya.. the cognitive load .. well.. it increased dramatically ;-) increased cognitive load bad! // ========================================== #include <stdio.h> #include <stdlib.h> #include <stdbool.h> #include <string.h> #include <assert.h> void displayResults(const char answer1, const char answer2); int main(void) { char answer1, answer2; while (true) { printf("Would you like in list (n=negatives, p=positives, b=both)? "); scanf_s(" %c", &answer1, 1); if (answer1 == 'n' || answer1 == 'p' || answer1 == 'b') { break; } printf("%c is not a valid answer. Try again.\n", answer1); } while (true) { printf("Would you like in list (e=evens, o=odds, b=both)? "); scanf_s(" %c", &answer2, 1); if (answer2 == 'e' || answer2 == 'o' || answer2 == 'b') { break; } printf("%c is not a valid answer. Try again.\n", answer2); } displayResults(answer1, answer2); putchar('\n'); return EXIT_SUCCESS; } void displayResults(const char answer1, const char answer2) { // NOTE: 0 is neither positive or negative, but is considered to be even int numbers[11] = {-3, 14, 47, -49, -30, 15, 4, -82, 99, 26, 0}; // an array to store results from answer1 int result1[sizeof(numbers) / sizeof(numbers[0])]; // the final array that consolidates the results from answer1 and answer2 // must be at least this size in case it stores all elements from numbers. int finalResult[sizeof(numbers) / sizeof(numbers[0])]; int result1Count = 0; // to keep count of number of elements aquired in answer1 int result2Count = 0; // to keep count of number of elements aquired in answer2 // my version of a string builder ;-) const int msgSize = 50; // should be large enough to hold the entire message. char *const resultMsg = (char *)malloc(msgSize); if (resultMsg == NULL) { exit(EXIT_FAILURE); // not enough memory!! really??!! } strcpy_s(resultMsg, 15, "\nHere are all "); switch (answer1) { case 'n': for (size_t i = 0; i < sizeof(numbers) / sizeof(int); i++) { if (numbers[i] < 0) result1[result1Count++] = numbers[i]; } memcpy((char *)resultMsg + 14, "[negative] \0", 12); break; case 'p': for (size_t i = 0; i < sizeof(numbers) / sizeof(int); i++) { if (numbers[i] > 0) result1[result1Count++] = numbers[i]; } memcpy((char *)resultMsg + 14, "[positive] \0", 12); break; case 'b': for (size_t i = 0; i < sizeof(numbers) / sizeof(int); i++) { result1[result1Count++] = numbers[i]; } break; default: // how could it ever get here?? printf("Bad input!!\n%c is not a valid answer.", answer1); assert(0); // don't waste my time! } // debug /* { printf("\n[ result1Count after processing answer1 is: %d ]\n ", result1Count); for (int i = 0; i < result1Count; i++) { printf("%d ", result1[i]); } putchar('\n'); } */ switch (answer2) { case 'e': for (int i = 0; i < result1Count; i++) { if ((result1[i] % 2) == 0) finalResult[result2Count++] = result1[i]; } if (answer1 == 'b') { memcpy((char *)resultMsg + 14, "[even]\0", 7); } else { memcpy((char *)resultMsg + 25, "[even]\0", 7); } break; case 'o': for (int i = 0; i < result1Count; i++) { if ((result1[i] % 2) != 0) finalResult[result2Count++] = result1[i]; } if (answer1 == 'b') { memcpy((char *)resultMsg + 14, "[odd]\0", 6); } else { memcpy((char *)resultMsg + 25, "[odd]\0", 6); } break; case 'b': for (int i = 0; i < result1Count; i++) { finalResult[result2Count++] = result1[i]; } break; default: // how could it ever get here?? printf("Bad input!!\n%c is not a valid answer.", answer2); assert(0); // don't waste my time! } // debug /* { printf("\n[ result2Count after processing answer2 is: %d ]\n ", result2Count); for (int i = 0; i < result2Count; i++) { printf("%d ", finalResult[i]); } putchar('\n'); } */ // sort the part of the array that we're interested in, in ascending order. int t; for (int i = 0; i < result2Count; i++) { for (int j = i + 1; j < result2Count; j++) { if (finalResult[i] > finalResult[j]) { t = finalResult[i]; finalResult[i] = finalResult[j]; finalResult[j] = t; } } } printf("%s numbers:\n", resultMsg); // print all the elements of the array for (int i = 0; i < result2Count; i++) { printf("%d ", finalResult[i]); } free(resultMsg); } // =====================================================
Nov 09 2021
parent reply Stanislav Blinov <stanislav.blinov gmail.com> writes:
On Tuesday, 9 November 2021 at 11:03:09 UTC, forkit wrote:

 They both produce exactly the same output.
But do vastly different things.
 But I tell ya.. the cognitive load .. well.. it increased 
 dramatically ;-)
Of course it did. Cuz you overthunk it. Dramatically. Your D version allocates memory, for no good reason. I mean, to store results, but you already have storage for them, so kinda pointless. Your C version, OTOH, stores results on stack (so again, why did you allocate for them in D?..), but allocates some "string builder" for... what, exactly? The program is filter, or sort + partition. Requires 0 allocations in C or D.
Nov 09 2021
next sibling parent reply forkit <forkit gmail.com> writes:
On Wednesday, 10 November 2021 at 04:54:58 UTC, Stanislav Blinov 
wrote:
 On Tuesday, 9 November 2021 at 11:03:09 UTC, forkit wrote:

 They both produce exactly the same output.
But do vastly different things.
 But I tell ya.. the cognitive load .. well.. it increased 
 dramatically ;-)
Of course it did. Cuz you overthunk it. Dramatically. Your D version allocates memory, for no good reason. I mean, to store results, but you already have storage for them, so kinda pointless. Your C version, OTOH, stores results on stack (so again, why did you allocate for them in D?..), but allocates some "string builder" for... what, exactly? The program is filter, or sort + partition. Requires 0 allocations in C or D.
Thanks for your feedback. This was not production code. It took a few minutes to do it on my pc, just for a little fun. So I doubt that I 'overthunk it' in such a small amount of time ;-) Also, my thought process began from the basis that the number data was immutable, and that the final data need to be stored, so that it could be manipulated etc... at will. I also wanted the use to a message, as to what they chose (hence the manipulation of memory for a message that could not be know in advance of the user making those choices). btw. My pc has 24GB of main memory, and my CPU 8MB L3 cache. So I really don't give a damn about allocations .. not one little bit ;-) Now if I were running a million processes across 1000's of servers, I probably would give a damn.
Nov 09 2021
next sibling parent Stanislav Blinov <stanislav.blinov gmail.com> writes:
On Wednesday, 10 November 2021 at 06:47:32 UTC, forkit wrote:

 btw. My pc has 24GB of main memory, and my CPU 8MB L3 cache. So 
 I really don't give a damn about allocations .. not one little 
 bit ;-)
That's not the point. The point is the program is doing unnecessary non-trivial work while introducing additional failure paths. It certainly has ways to go to reach Ali's AA solution, but still... To put things in perspective, the algorithm can easily complete before malloc even returns (heck, before it even starts executing). There's what, 11 cmovs at most? It would take several dozen instructions, a couple of loops and a few other branches just to find malloc when you first call it. Not to mention it itself making that syscall and setting up its bins... And I'm not even talking about optimization. Just, uh, non-pessimization.
Nov 09 2021
prev sibling parent reply russhy <russhy gmail.com> writes:
On Wednesday, 10 November 2021 at 06:47:32 UTC, forkit wrote:
 btw. My pc has 24GB of main memory, and my CPU 8MB L3 cache. So 
 I really don't give a damn about allocations .. not one little 
 bit ;-)
It's not a good mindset to have Give room for the unexpected, don't burn all of your options right now Having good foundation helps one to grow and scale faster than others Often i seen gamedevs write shitty code, "it's fine" they said, only to realize their game runs at 10FPS when they decide it's time to port it to the Switch (portable console) or when one decide to play on a laptop Or your server can no longer fit in the 128mb VPS instance, and you forced to pay the more expensive one, only because "it was fine" Having the right mindset helps not make these mistakes in the future Changing habits is hard, make sure to train yourself to pick the right one, early if possible
Nov 10 2021
next sibling parent reply "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Wed, Nov 10, 2021 at 10:17:48PM +0000, russhy via Digitalmars-d-learn wrote:
 On Wednesday, 10 November 2021 at 06:47:32 UTC, forkit wrote:
 btw. My pc has 24GB of main memory, and my CPU 8MB L3 cache. So I
 really don't give a damn about allocations .. not one little bit ;-)
It's not a good mindset to have Give room for the unexpected, don't burn all of your options right now Having good foundation helps one to grow and scale faster than others
[...] +1. Ironically, dmd itself is pretty care-free about allocating memory (in the name of compile speed -- after all, everybody has GBs of RAM to spare, but nobody wants to wait, right?). As a result, I cannot compile even simple programs on a low-memory system because the compiler runs out of memory and crashes before it can finish compiling. What good is a super-fast compiler that cannot finish compiling before it uses too much memory? Because of this, I have not dared to introduce D to my colleagues -- if they see what dmd does on the kind of low-memory embedded systems that we work on, they'd get such a bad impression of D they'll never ever want to hear about it again. :-/ T -- Verbing weirds language. -- Calvin (& Hobbes)
Nov 10 2021
next sibling parent reply =?UTF-8?Q?Ali_=c3=87ehreli?= <acehreli yahoo.com> writes:
On 11/10/21 3:05 PM, H. S. Teoh wrote:

 I cannot compile
 even simple programs on a low-memory system because the compiler runs
 out of memory
Did the -lowmem switch help in some cases? Is -betterC any better? ;) Ali
Nov 10 2021
parent "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Wed, Nov 10, 2021 at 03:13:08PM -0800, Ali Çehreli via Digitalmars-d-learn
wrote:
 On 11/10/21 3:05 PM, H. S. Teoh wrote:
 
 I cannot compile even simple programs on a low-memory system because
 the compiler runs out of memory
Did the -lowmem switch help in some cases?
On my (high-mem) home PC, it does help to reduce the memory footprint somewhat. But unfortunately, not enough to make compilation work on the low-mem systems on all except the most trivial of programs. So still no-go.
 Is -betterC any better? ;)
[...] Have not tried. Maybe I'll give it a shot when I have some time. I'm not a fan, though. Using -betterC loses some of the key advantages D offers over C, and would probably not be incentive enough for my colleagues to consider adopting D. (We had tried C++ before and given up on it, so whatever is going to displace C in this space better offer a LOT more than C++ ever did. Simply being yet another variant of C isn't going to cut it.) T -- It is the quality rather than the quantity that matters. -- Lucius Annaeus Seneca
Nov 10 2021
prev sibling parent reply forkit <forkit gmail.com> writes:
On Wednesday, 10 November 2021 at 23:05:06 UTC, H. S. Teoh wrote:
 On Wed, Nov 10, 2021 at 10:17:48PM +0000, russhy via 
 Digitalmars-d-learn wrote:
 On Wednesday, 10 November 2021 at 06:47:32 UTC, forkit wrote:
 btw. My pc has 24GB of main memory, and my CPU 8MB L3 cache. 
 So I really don't give a damn about allocations .. not one 
 little bit ;-)
It's not a good mindset to have Give room for the unexpected, don't burn all of your options right now Having good foundation helps one to grow and scale faster than others
[...] +1. Ironically, dmd itself is pretty care-free about allocating memory (in the name of compile speed -- after all, everybody has GBs of RAM to spare, but nobody wants to wait, right?). As a result, I cannot compile even simple programs on a low-memory system because the compiler runs out of memory and crashes before it can finish compiling. What good is a super-fast compiler that cannot finish compiling before it uses too much memory? Because of this, I have not dared to introduce D to my colleagues -- if they see what dmd does on the kind of low-memory embedded systems that we work on, they'd get such a bad impression of D they'll never ever want to hear about it again. :-/ T
I still remember compiling code on my 286x86 ... talk about low memory..whoaaah. These days, I have a 4GB ramdisk, put all the dmd/phobos..etc source code into that, and everything is read/compiled completely in memory, in seconds. The slowest part is copying the compilation back to disk, but even that happens so fast I don't even see it happen. Worrying about an extra allocation here or there seems kinds trivial over here ;-)
Nov 10 2021
parent reply "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Wed, Nov 10, 2021 at 11:39:40PM +0000, forkit via Digitalmars-d-learn wrote:
[...]
 I still remember compiling code on my 286x86 ... talk about low
 memory..whoaaah.
That's nothing! ;-) When I was a kid, I programmed a computer that had only 48K of RAM (that's 48 *kilo*bytes, not megabytes!). The address space was 64K (16-bit), but beyond the 48K boundary was occupied by ROM which cannot be modified.
 These days, I have a 4GB ramdisk, put all the dmd/phobos..etc source
 code into that, and everything is read/compiled completely in memory,
 in seconds.  The slowest part is copying the compilation back to disk,
 but even that happens so fast I don't even see it happen.
In all likelihood, it isn't actually copying everything back to disk in that instant, but rather sitting in the HD cache while the controller slowly writes it to disk in the background. :-D (Well, before that, in the OS cache.)
 Worrying about an extra allocation here or there seems kinds trivial
 over here ;-)
It depends on what you're doing. In the OP's example, yeah worrying about allocations is totally blowing things out of proportions. But if you're in a time-constrained inner loop, you do *not* want to be allocating memory without a second thought, lest you provoke the ire of the GC and get a stop-the-world pause in the wrong moment. E.g., when your radiotherapy dosage controller is just about to shut off the radiation beam, and the extra pause can mean death from overdose. :-P Or y'know, the more important thing these days -- hundreds of your gamers will complain about jerkiness or lower framerates in their totally-important 60fps GPU-raytraced game. ;-) Or, on a more serious note, if you're trying to solve a mathematically hard problem, needless allocations can mean the difference between getting the answer next week vs. the next century. Sometimes these things *do* add up. T -- MSDOS = MicroSoft's Denial Of Service
Nov 10 2021
next sibling parent reply forkit <forkit gmail.com> writes:
On Thursday, 11 November 2021 at 00:11:07 UTC, H. S. Teoh wrote:
 On Wed, Nov 10, 2021 at 11:39:40PM +0000, forkit via 
 Digitalmars-d-learn wrote: [...]
 I still remember compiling code on my 286x86 ... talk about 
 low memory..whoaaah.
... But if you're in a time-constrained inner loop, you do *not* want to be allocating memory without a second thought, lest you provoke the ire of the GC and get a stop-the-world pause in the wrong moment. E.g., when your radiotherapy dosage controller is just about to shut off the radiation beam, and the extra pause can mean death from overdose. :-P ..
Silly me.. if only I had used v2.098.0 ... I might still be alive. https://dlang.org/changelog/2.098.0.html#forkgc
Nov 10 2021
parent "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Thu, Nov 11, 2021 at 01:09:26AM +0000, forkit via Digitalmars-d-learn wrote:
 On Thursday, 11 November 2021 at 00:11:07 UTC, H. S. Teoh wrote:
 On Wed, Nov 10, 2021 at 11:39:40PM +0000, forkit via Digitalmars-d-learn
 wrote: [...]
 I still remember compiling code on my 286x86 ... talk about low
 memory..whoaaah.
... But if you're in a time-constrained inner loop, you do *not* want to be allocating memory without a second thought, lest you provoke the ire of the GC and get a stop-the-world pause in the wrong moment. E.g., when your radiotherapy dosage controller is just about to shut off the radiation beam, and the extra pause can mean death from overdose. :-P ..
Silly me.. if only I had used v2.098.0 ... I might still be alive. https://dlang.org/changelog/2.098.0.html#forkgc
😂 T -- I am not young enough to know everything. -- Oscar Wilde
Nov 11 2021
prev sibling parent reply Stanislav Blinov <stanislav.blinov gmail.com> writes:
On Thursday, 11 November 2021 at 00:11:07 UTC, H. S. Teoh wrote:

 It depends on what you're doing. In the OP's example, yeah 
 worrying about allocations is totally blowing things out of 
 proportions.
But that's the thing. How would one ever learn to know where that dividing line is if all the learning material they see teaches them the opposite - to not know or care? 'Twas a simple task: traverse an array and print numbers out of it based on a predicate. That is all the original program did. How does doing (LOTS) more than that make any of it easier to understand, let alone equivalent to execute? forkit says: "if I was writing millions of processes across 1000s of servers..." No. Just... no. If I've only ever written "convenient" pessimized code, I won't magically start lighting up those wasted transistors just because I got a new job. I'll just be writing the same "convenient" pessimized code, only it would now span 1000s of servers. Which is the exact effing situation that we're in already!
Nov 11 2021
parent reply forkit <forkit gmail.com> writes:
On Thursday, 11 November 2021 at 21:13:03 UTC, Stanislav Blinov 
wrote:
 On Thursday, 11 November 2021 at 00:11:07 UTC, H. S. Teoh wrote:

 It depends on what you're doing. In the OP's example, yeah 
 worrying about allocations is totally blowing things out of 
 proportions.
But that's the thing. How would one ever learn to know where that dividing line is if all the learning material they see teaches them the opposite - to not know or care?
It's called 'staged learning'. Staged learning is the only way for humans to learn, due to the limitations of the human cognitive system. Specifically, the way short-term memory and long-term memory facilitate learning. Those who lack this understanding of how humans learn, tend to throw too much at novices. Also, this apparent drive towards requiring novices to understand the implications of their code, in terms of optimising the assembly that gets produced, is just nonsense. They'll never get pass the for loop!
Nov 11 2021
parent reply Stanislav Blinov <stanislav.blinov gmail.com> writes:
On Thursday, 11 November 2021 at 22:10:04 UTC, forkit wrote:

 It's called 'staged learning'.

 Staged learning is the only way for humans to learn, due to the 
 limitations of the human cognitive system. Specifically, the 
 way short-term memory and long-term memory facilitate learning.

 Those who lack this understanding of how humans learn, tend to 
 throw too much at novices.
Like making a simple program do a bunch of extra work for literally no reason?
 Also, this apparent drive towards requiring novices to 
 understand the implications of their code, in terms of 
 optimising the assembly that gets produced, is just nonsense. 
 They'll never get pass the for loop!
This has nothing to do with "optimising the assembly".
Nov 11 2021
next sibling parent foxit <foxit gmail.com> writes:
On Friday, 12 November 2021 at 01:05:15 UTC, Stanislav Blinov 
wrote:
 On Thursday, 11 November 2021 at 22:10:04 UTC, forkit wrote:

 It's called 'staged learning'.

 Staged learning is the only way for humans to learn, due to 
 the limitations of the human cognitive system. Specifically, 
 the way short-term memory and long-term memory facilitate 
 learning.

 Those who lack this understanding of how humans learn, tend to 
 throw too much at novices.
Like making a simple program do a bunch of extra work for literally no reason?
I think what you're missing here, is that this thread was about how to bring some C code into D, and do it some kinda 'D style'. But this thread clearly demonstrates, there is no 'D style'. Stop being so combative ;-) let people be creative first, performance oriented second (or third.. or .....). If we all wrote code the same way, we'd likely all be thinking the same way... and that would not be good. If people want code that looks the same as everyone elses, and forces you to think in the same way as everyone else, they can go use Go ;-)
Nov 11 2021
prev sibling parent forkit <forkit gmail.com> writes:
On Friday, 12 November 2021 at 01:05:15 UTC, Stanislav Blinov 
wrote:
 On Thursday, 11 November 2021 at 22:10:04 UTC, forkit wrote:

 It's called 'staged learning'.

 Staged learning is the only way for humans to learn, due to 
 the limitations of the human cognitive system. Specifically, 
 the way short-term memory and long-term memory facilitate 
 learning.

 Those who lack this understanding of how humans learn, tend to 
 throw too much at novices.
Like making a simple program do a bunch of extra work for literally no reason?
 Also, this apparent drive towards requiring novices to 
 understand the implications of their code, in terms of 
 optimising the assembly that gets produced, is just nonsense. 
 They'll never get pass the for loop!
This has nothing to do with "optimising the assembly".
also, I think it's important not to conflate, code that doesn't perform well, with code that is not optimal. it doesn't take very long as a developer, before you realise nobodys likes slow software ;-) so performance will ALWAYS be front of mind, once you reach that point. We don't need people telling us your code needs to written so that it performs well. But even fast software is not necessarily optimised, and likely far from it in many scenarios... and getting worse it seems... which is ok, as long as faster devices keep rolling out I guess.. most people are developers (incl me), not programmers per se, and don't have the time to understand the ins and outs of how code executes on hardware, and how one library finction interacts with another.....etc... and so are not really in a position to optimise it. They are more interested in ensuring the solution they give to their users is not slow. That's what matters to them, and their users. An app that use 3GB of your memory, when (if optimised) really could reduce that to 1GB, sounds great, in principle. But what effect will that optimised code have in terms of bugs and maintainance? So there are tradeoffs that do genuiely need to be considered, and circumstances differ. btw. None of the solutions in this thread are slow..not by any means... and its certainly likely that none are optimal. Hopefully the compiler and library are doing their very best to make it optimal ;-)
Nov 11 2021
prev sibling parent reply forkit <forkit gmail.com> writes:
On Wednesday, 10 November 2021 at 22:17:48 UTC, russhy wrote:
 On Wednesday, 10 November 2021 at 06:47:32 UTC, forkit wrote:
 btw. My pc has 24GB of main memory, and my CPU 8MB L3 cache. 
 So I really don't give a damn about allocations .. not one 
 little bit ;-)
 Having the right mindset helps not make these mistakes in the 
 future

 Changing habits is hard, make sure to train yourself to pick 
 the right one, early if possible
Umm.. you kinda missed the last part of my post... ..where I said..'Now if I were running a million processes across 1000's of servers, I probably would give a damn.' C'mon... nothing in my code was 'unacceptable' in terms of speed or efficiency. Making code transformations to improve speed and efficieny are important, but secondary. A newcomer cannot improve code that they do not understand ;-) Picking understandable code first, IS right. In any case, I say again, this thread is not about writing performance code per se, but about presenting code to new-comers, that they can make some sense of. Taking some C code, and writing/presenting it in D (or vica-versa) in such a way that you can longer make any sense of it, is kinda futile. I doubt the original op will ever come back to D, after seeing some of those examples that were provided ;-)
Nov 10 2021
parent reply Stanislav Blinov <stanislav.blinov gmail.com> writes:
On Wednesday, 10 November 2021 at 23:15:09 UTC, forkit wrote:
 On Wednesday, 10 November 2021 at 22:17:48 UTC, russhy wrote:
 On Wednesday, 10 November 2021 at 06:47:32 UTC, forkit wrote:
 btw. My pc has 24GB of main memory, and my CPU 8MB L3 cache. 
 So I really don't give a damn about allocations .. not one 
 little bit ;-)
 Having the right mindset helps not make these mistakes in the 
 future

 Changing habits is hard, make sure to train yourself to pick 
 the right one, early if possible
Umm.. you kinda missed the last part of my post... ..where I said..'Now if I were running a million processes across 1000's of servers, I probably would give a damn.'
Your CPU executes code speculatively, and in parallel. That's just the way it is, it's how the machine works. Therefore, you simply cannot afford to NOT think about that. You're just wasting your machine time if you're not caring about that. Consequently, you're wasting your time, someone else's time, and, well, money. No, it's not a million processes across 1000s of servers, it's at least two processes across n cores, each of which has m ALUs. (At least two because the OS is involved). But it's two processes from you, two processes from me, four from the other guy, and pretty soon you have a monster that struggles to utilize even a tenth of your machine. All because "I'll care about it tomorrow".
 C'mon... nothing in my code was 'unacceptable' in terms of 
 speed or efficiency.

 Making code transformations to improve speed and efficieny are 
 important, but secondary. A newcomer cannot improve code that 
 they do not understand ;-)
Yes, optimization is hard. Pessimization, though, is laughably easy, and should be avoided at all costs. "I don't care" is the number 1 reason for the atrocious situation with software that we're in right now. And people tend to come up with all sorts of ridiculous excuses, but most of them, distilled, do amount to "I don't care". My phone is a thousand times faster, and has two million times more memory, than the thing that guided Apollo 11 to the Moon. And yet it sometimes takes longer to react to my keystrokes than roundtrip for a radio signal to the Moon *and* back. My desktop is two times faster, and has eight times more memory, than my phone. But it consistently takes THREE TIMES the roundtrip of a radio signal to the Moon and back to start Visual Studio. Heck, it will take longer than the roundtrip of a radio signal to the Moon and back to post this message after I hit "Send". And I'm reasonably certain this news server is not on the Moon. This all is, plainly, ridiculous.
 Picking understandable code first, IS right.
No. "Understability" is subjective. Show me some code in Scala or Fortran, I won't make heads or tails of it, even though it may be perfectly obvious to the next guy who also never saw either language. What's "right" is writing code that doesn't perform, or cause, any unnecessary work. It may not be fast, but at least it won't be slow for no reason.
 In any case, I say again, this thread is not about writing 
 performance code per se, but about presenting code to 
 new-comers, that they can make some sense of.
And how does invoking extra work help with that? Coupled with not even explaining what that extra work is and why it is there?
 Taking some C code, and writing/presenting it in D (or 
 vica-versa) in such a way that you can longer make any sense of 
 it, is kinda futile.
Original C code from the first post can only fail on I/O, which is arguably out of your control. And the meat of it amounts to 10 conditional stores. Your implementations, in both C and D, are a very, very far distance away from that. Like I mentioned before, the whole algorithm can already complete even before a single `malloc` call starts executing. Not caring about *that* is just bad engineering. If you're writing C, or D, you're not writing pulp fiction for the masses. There are other languages for that.
Nov 11 2021
next sibling parent reply =?UTF-8?Q?Ali_=c3=87ehreli?= <acehreli yahoo.com> writes:
On 11/11/21 11:34 AM, Stanislav Blinov wrote:

 Pessimization, though, is laughably easy, and
 should be avoided at all costs.
I am not passionate about this topic at all and I am here mostly because I have fun in this forum. So, I am fine in general. However, I don't agree that pessimization should be avoided at all costs. I like D because it allows me to be as sloppy as I want to fix my code later on when it really matters.
 Not caring about *that* is just bad engineering.
There wasn't a problem statement with the original code. So, we understood and valued it according to our past experiences. For example, most of us assumed the program was about 10 integers but I am pretty sure that array was just an example and the program was meant to deal with larger number of arrays. Another example is, you seem to value performance over maintainability because you chose to separate the selection letters without getting any programmatic help from any tool: write("Would you like in list (e=evens, o=odds, b=both)? "); readf(" %c", &even); if ((negativity == 'b') && (even == 'b')) For example, the 'b's in that last line may be left behind unmodified if someone changes the help text alone. Someone may find that kind of coding "bad engineering" that shoul be avoided at all cost. (Not to defend myself but my associative array was exactly because I could not bring myself to separate those selection letters from the help text. I simply could not show unmaintainable code to a beginner.) I don't think there is much more to see here: A simple C program, liberties taken for fun in D, pessimization is bad, unmaintainability is bad, yes. Ali
Nov 11 2021
parent Stanislav Blinov <stanislav.blinov gmail.com> writes:
On Thursday, 11 November 2021 at 21:56:19 UTC, Ali Çehreli wrote:
 On 11/11/21 11:34 AM, Stanislav Blinov wrote:

 Pessimization, though, is laughably easy, and
 should be avoided at all costs.
I am not passionate about this topic at all and I am here mostly because I have fun in this forum. So, I am fine in general. However, I don't agree that pessimization should be avoided at all costs. I like D because it allows me to be as sloppy as I want to fix my code later on when it really matters.
And when is that? And why is it not now? You mean prototyping? You can do that in any language, not sure what's special about D here. Sure, prototype away. No one gets everything right in a single keystroke.
 Not caring about *that* is just bad engineering.
There wasn't a problem statement with the original code. So, we understood and valued it according to our past experiences. For example, most of us assumed the program was about 10 integers but I am pretty sure that array was just an example and the program was meant to deal with larger number of arrays.
What difference does that make? You still don't want to do any unnecessary work, whether you're dealing with one puny array or a million of them.
 Another example is, you seem to value performance over 
 maintainability because you chose to separate the selection 
 letters without getting any programmatic help from any tool:
I didn't "choose" that. That's Siarhei Siamashka's version, fixed up to use `each` instead of `map!text.join`, because latter serves no useful purpose. That is a weird comparison anyway. Performance OVER maintainability? There's nothing "more performant" or "less maintainable" in the input handling code, as it's the same as original.
   write("Would you like in list (e=evens, o=odds, b=both)? ");
   readf(" %c", &even);

   if ((negativity == 'b') && (even == 'b'))

 For example, the 'b's in that last line may be left behind 
 unmodified if someone changes the help text alone.
Let me see if I get this straight now... are you seriously talking about protecting against this program being altered by a goldfish? Because in that case, I'd best not write any code altogether. Someone someday may put an extra semicolon somewhere, the thing would stop compiling, and I'll be totally ruined. ...Perhaps let's actually stay on this planet?
 Someone may find that kind of coding "bad engineering" that 
 shoul be avoided at all cost.
Sure. Someone definitely may. It'd certainly be nice to decouple input from logic. That doesn't take 14 times more code and AAs to do though. Just sayin' ;)
 (Not to defend myself but my associative array was exactly 
 because I could not bring myself to separate those selection 
 letters from the help text. I simply could not show 
 unmaintainable code to a beginner.)
The original UI code is four lines. Four. Not fool-proof, input's not even validated. But four lines. Yours is fifty five, just to construct and present the UI and read input. Consequently, original program is about 14 times easier to maintain than yours. What did I miss?
Nov 11 2021
prev sibling parent forkit <forkit gmail.com> writes:
On Thursday, 11 November 2021 at 19:34:42 UTC, Stanislav Blinov 
wrote:
 Original C code from the first post can only fail on I/O, which 
 is arguably out of your control. And the meat of it amounts to 
 10 conditional stores. Your implementations, in both C and D, 
 are a very, very far distance away from that. Like I mentioned 
 before, the whole algorithm can already complete even before a 
 single `malloc` call starts executing. Not caring about *that* 
 is just bad engineering.
Actually, that's an interesting comment, as it clearly indicates where we differ in perspective when we read that initial code. The 'meat' of it, from my perspective, is 'there's someone using this code'. So why is there no code to verify that input, and handle incorrect input in a user friendly manner. The rest of the coding is kinda automatic reflex.. use a for loop.. or a switch..use an array or a vector..separate concerns into functions...I really don't care what or how you do that part (as long as it's not code I need to understand or maintain). But don't give me a program that says enter a, b or c, but Hence the 'addition's I made ;-) I think your perspective, and mine (and others) are ALL valid.
Nov 11 2021
prev sibling parent forkit <forkit gmail.com> writes:
On Wednesday, 10 November 2021 at 04:54:58 UTC, Stanislav Blinov 
wrote:
 On Tuesday, 9 November 2021 at 11:03:09 UTC, forkit wrote:

 They both produce exactly the same output.
But do vastly different things.
 But I tell ya.. the cognitive load .. well.. it increased 
 dramatically ;-)
Of course it did. Cuz you overthunk it. Dramatically. Your D version allocates memory, for no good reason. I mean, to store results, but you already have storage for them, so kinda pointless. Your C version, OTOH, stores results on stack (so again, why did you allocate for them in D?..), but allocates some "string builder" for... what, exactly? The program is filter, or sort + partition. Requires 0 allocations in C or D.
And.. in any case, the take away from this thread should not be about nonallocating coding, but rather the interesting comment from the originl op.. "Wow! your code seem so nice, I like it although I don't know how exactly it works."
Nov 09 2021
prev sibling parent reply forkit <forkit gmail.com> writes:
On Tuesday, 2 November 2021 at 23:45:39 UTC, pascal111 wrote:
 Next code originally was a classic C code I've written, it's 
 pure vertical thinking, now, I converted it successfully to D 
 code, but I think I made no much changes to make it has more 
 horizontal thinking style that it seems D programmers care in 
 horizontal thinking style. Is there any additions I can make in 
 the code to make it suitable with D style or it's fine?
ok.. for a more on topic response.. First: Please name your variables sensibly: char negativity, even; // grrr!!! char answer1, answer2; // makes so much more sense Second: You need to use D-style syntax in your array declaration int numbers[10] = [-3, 14, 47, -49, -30, 15, 4, -82, 99, 26]; // C style int[10] numbers = [-3, 14, 47, -49, -30, 15, 4, -82, 99, 26]; // D style Third: you're asking for trouble in your for loop declaration. for(int i = 0; i < 10; ++i) // grrr!! What if you counted up your elements incorrectly? for(int i = 0; i < sizeof(numbers) / sizeof(int); ++i) // is so much safer - in C style for(int i = 0; i < numbers.length; ++i) // is so much safer - in D style Finally, D is multi paradigm. That's probably the first (and most important) thing you should know about D. Yes, you can write C style easy, and in many cases, that's just fine. You can also write in other styles. But sometimes it is worthwhile rewriting code differently, to see what advantages, if any, comes about. D is a language where you can actually do just that. Above is a good (although very basic) example - i.e. change the way you define a for loop, so that it's safer, simpler, and more maintainable. Also, use of lambdas, UCFS, etc.. (which is probably what you meant by 'horizontal' code), if used sensibly, can remarkably reduce and simplify code, as well as contributing to the maintainability of that code. Thankfully, D is multiparadigm (which is its best and worst feature), and so it lets you can experiment with different styles. Try doing this in C, Go, Rust...
Nov 11 2021
next sibling parent reply kdevel <kdevel vogtner.de> writes:
On Thursday, 11 November 2021 at 22:30:12 UTC, forkit wrote:
[...]
      for(int i = 0; i < sizeof(numbers) / sizeof(int); ++i) // 
 is so much safer - in C style
I made it even safer: for (int i = 0; i < sizeof numbers / sizeof *numbers; ++i) Maybe the type of numbers is changed in the future. sizeof is an operator which needs parentheses around its argument only for types. sizeof (non-type-arg) alleges a binding that does not exist: #include <stdio.h> struct bar { long l1; long l2; }; #define S(a) #a, (long unsigned) a int main () { struct bar *b; printf ("%25s = %lu\n", S(sizeof(*b))); printf ("%25s = %lu\n", S(sizeof(*b).l1)); printf ("%25s = %lu\n", S(sizeof(b)->l1)); return 0; } compiles (!) and gives: sizeof(*b) = 16 sizeof(*b).l1 = 8 sizeof(b)->l1 = 8
Nov 11 2021
parent foxit <foxit gmail.com> writes:
On Thursday, 11 November 2021 at 23:41:48 UTC, kdevel wrote:
 On Thursday, 11 November 2021 at 22:30:12 UTC, forkit wrote:
 [...]
      for(int i = 0; i < sizeof(numbers) / sizeof(int); ++i) // 
 is so much safer - in C style
I made it even safer: for (int i = 0; i < sizeof numbers / sizeof *numbers; ++i)
(void*)*numbers = NULL; ..don't you just love C ;-)
Nov 11 2021
prev sibling parent reply pascal111 <judas.the.messiah.111 gmail.com> writes:
On Thursday, 11 November 2021 at 22:30:12 UTC, forkit wrote:
 On Tuesday, 2 November 2021 at 23:45:39 UTC, pascal111 wrote:
[...]
ok.. for a more on topic response.. First: Please name your variables sensibly: char negativity, even; // grrr!!! char answer1, answer2; // makes so much more sense [...]
I touch that D is big language, it's not small like standard C. This will cost me much studying, so I think I need slow down and learn it step by step.
Nov 13 2021
parent reply forkit <forkit gmail.com> writes:
On Saturday, 13 November 2021 at 23:02:15 UTC, pascal111 wrote:
 I touch that D is big language, it's not small like standard C. 
 This will cost me much studying, so I think I need slow down 
 and learn it step by step.
Yes. C is so much smaller, and thus simpler (till you wanna do something complex) But C also makes it 'simpler' to shoot yourself in the foot ;-) Even with your simple C code, which is so easily tranposed to D, you already benefit from: - variables being always initialised before use (i.e no need to initalise i in your for loop, in D) - array indices being automatically checked for out-of-bounds (i.e. i < 10 ... in D.. it becomes.. numbers.length ) so you can make your simple code, even 'simpler' in D ;-)
Nov 13 2021
parent pascal111 <judas.the.messiah.111 gmail.com> writes:
On Sunday, 14 November 2021 at 04:29:53 UTC, forkit wrote:
 On Saturday, 13 November 2021 at 23:02:15 UTC, pascal111 wrote:
 I touch that D is big language, it's not small like standard 
 C. This will cost me much studying, so I think I need slow 
 down and learn it step by step.
Yes. C is so much smaller, and thus simpler (till you wanna do something complex) But C also makes it 'simpler' to shoot yourself in the foot ;-) Even with your simple C code, which is so easily tranposed to D, you already benefit from: - variables being always initialised before use (i.e no need to initalise i in your for loop, in D) - array indices being automatically checked for out-of-bounds (i.e. i < 10 ... in D.. it becomes.. numbers.length ) so you can make your simple code, even 'simpler' in D ;-)
Thanks! I won't hide my real intention. Learning C to learning D is like the case of doctor Jekyll and Mr. Hyde, if I'm in the place of Jekyll, I treat Hyde as a son and I want to teach him programming, and we can't do that with C because it belongs to vertical thinking, while D belongs to Hyde or the horizontal thinking.
Nov 15 2021