digitalmars.D.learn - about pointer syntax
- spir (44/44) Oct 14 2010 Hello,
- bearophile (47/52) Oct 14 2010 I have modified your code a little:
- spir (65/127) Oct 14 2010 ymbol table as linked list: see prototype code of the structs below. (Hi...
- bearophile (28/36) Oct 14 2010 Not putting a value, unless it's different from the standard initializat...
- bearophile (1/2) Oct 14 2010 I meant associative array, sorry.
- Andrej Mitrovic (5/8) Oct 14 2010 I'm not sure, but I think function pointers (the C syntax ones, not
Hello, As a way to start learning D by practicing, I'm trying to implement a symbo= l table as linked list: see prototype code of the structs below. (Hints abo= ut good D coding welcome :-) 2 little questions about pointers: 1. To please the compiler, I had to wrap dereferencing in parens, like in "= (*symbol).name". Is this just normal (for disambiguation)? 2. Just noticed the compiler accepts "symbol.name", while symbol is a point= er: is there implicit dereferencing of pointers to structs? If yes, does th= is also apply to pointers to arrays (for information, this what Oberon does= ). And a note: had forgotten to add an empty main(), just for compiling: the l= inker produced a rather big amount of error text without any hint to the ac= tual issue. Maybe dmd could cope with that before calling gcc? Finally: the reference is rather harsh for me, esp there are very few examp= le (I have few practice of C, and none of C++); the bits of tutorials I fou= nd are too light or just started (toc points to empty pages). Is there anyw= here online a kind of D programming guide, even not polished or possibly un= finished (I know about the book; maybe I'll order it, but in meantime...). Thank you, Denis =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D code =3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D struct Symbol { string name =3D "" ; int element =3D 0 ; Symbol* next =3D null ; } struct List { Symbol* first =3D null ; int element(string name) { Symbol* symbol =3D this.first ; while (symbol) { if ((*symbol).name =3D=3D name) {return (*symbol).element ;} ; symbol =3D (*symbol).next ; } return 0 ; } } =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D -- -- -- -- -- -- -- vit esse estrany =E2=98=A3 spir.wikidot.com
Oct 14 2010
spir:As a way to start learning D by practicing, I'm trying to implement a symbol table as linked list: see prototype code of the structs below. (Hints about good D coding welcome :-)I have modified your code a little: struct Symbol { string name; int element; Symbol* next; this(string n, int e, Symbol* s=null) { name = n; element = e; next = s; } } struct List { Symbol* first; int element(string name) { for (auto symbol = this.first; symbol != null; symbol = symbol.next) if (symbol.name == name) return symbol.element; return 0; } } void main() { auto l = List(new Symbol("baz", 3, new Symbol("bar", 2, new Symbol("foo", 1)))); assert(l.element("bar") == 2); } - There's no need to initialize int to 0, string to "", pointers to null, etc, the compiler does it for you on default. Each type has a default init value (for floating point values it uses a NaN). - Generally don't put a space before the ending semicolon. - Four spaces indent and no space before the "*" of the pointer, as you have done, is OK. - Using a while loop as you have done is OK, I have used a for loop just to show a shorter alternative. - It's generally better to put one or two blank lines before structs, functions, etc - (*symbol).name is written symbol.name in D. - After an { generally a \n is used, there's no need to use the ; after the } - using 0 as error return value is sometimes OK, but also keep in mind that exceptions are present. - while(symbol) is acceptable, but some people prefer to put an explicit comparison to make the code more readable. - sometimes using "auto" helps. - In D linked lists are doable, but much less used, think about using a dynamic array, or even in this case an associative array: void main() { auto aa = ["foo": 1, "bar": 2, "baz": 3]; assert(aa["bar"] == 2); }1. To please the compiler, I had to wrap dereferencing in parens, like in "(*symbol).name". Is this just normal (for disambiguation)? 2. Just noticed the compiler accepts "symbol.name", while symbol is a pointer: is there implicit dereferencing of pointers to structs? If yes, does this also apply to pointers to arrays (for information, this what Oberon does).Generally the field dereferencing doesn't require the "(*symbol).name", in D you use "symbol.name". Pointers to arrays are possible, but quite uncommon in D.And a note: had forgotten to add an empty main(), just for compiling: the linker produced a rather big amount of error text without any hint to the actual issue. Maybe dmd could cope with that before calling gcc?I agree, I have bug report 4680 open on something similar: http://d.puremagic.com/issues/show_bug.cgi?id=4680Finally: the reference is rather harsh for me, esp there are very few example (I have few practice of C, and none of C++); the bits of tutorials I found are too light or just started (toc points to empty pages). Is there anywhere online a kind of D programming guide, even not polished or possibly unfinished (I know about the book; maybe I'll order it, but in meantime...).The D2 documentation isn't abundant yet :-) Bye, bearophile
Oct 14 2010
On Thu, 14 Oct 2010 17:16:23 -0400 bearophile <bearophileHUGS lycos.com> wrote:spir: =20ymbol table as linked list: see prototype code of the structs below. (Hints= about good D coding welcome :-)As a way to start learning D by practicing, I'm trying to implement a s==20 I have modified your code a little: =20 struct Symbol { string name; int element; Symbol* next; =20 this(string n, int e, Symbol* s=3Dnull) { name =3D n; element =3D e; next =3D s; } } =20 struct List { Symbol* first; =20 int element(string name) { for (auto symbol =3D this.first; symbol !=3D null; symbol =3D sym=bol.next)if (symbol.name =3D=3D name) return symbol.element; return 0; } } =20 void main() { auto l =3D List(new Symbol("baz", 3, new Symbol("bar", 2, new Symbol(="foo", 1))));assert(l.element("bar") =3D=3D 2); }Thank you very much! That's exactly what I need to learn good practice, eve= n more with comments below. (Hope you don't mind if I send other bits of co= de to be improved that way?)- There's no need to initialize int to 0, string to "", pointers to null,=etc, the compiler does it for you on default. Each type has a default init= value (for floating point values it uses a NaN). Right. I think at keeping explicit defaults like "int element =3D 0" for do= cumentation. It means "that's precisely what I want as default value", as o= pposed to just the language's "init". (So, for Symbol fields, I would only = write element & next defaults explicitely, since name has no meaningful def= ault: it must be provided.)- Generally don't put a space before the ending semicolon. - Four spaces indent and no space before the "*" of the pointer, as you h=ave done, is OK.- It's generally better to put one or two blank lines before structs, fun=ctions, etc (About ';', I like to separate actual code from grammatical separators, whi= ch are just noise to my eyes. If I ever write a lib for public use, I'll fo= llow such styling guidelines ;-)- Using a while loop as you have done is OK, I have used a for loop just =to show a shorter alternative. Thanks, as I said I'm not used to PLs of the C family. Wouldn't have ever t= hought that the "stepping" statement of a for loop can be something else as= incrementation.- (*symbol).name is written symbol.name in D.Very good.- After an { generally a \n is used, there's no need to use the ; after t=he } Right.- using 0 as error return value is sometimes OK, but also keep in mind th=at exceptions are present. ;-) Was just a placeholder before I decide how to cope with "finding failur= e".- while(symbol) is acceptable, but some people prefer to put an explicit =comparison to make the code more readable. Right, guess you mean while(symbol !=3D null)?- sometimes using "auto" helps.I need to explore this further (what's the actual purpose of "auto").- In D linked lists are doable, but much less used, think about using a d=ynamic array, or even in this case an associative array:void main() { auto aa =3D ["foo": 1, "bar": 2, "baz": 3]; assert(aa["bar"] =3D=3D 2); }Yes, it was just an exercise. For curiosity, I intend to benchmark lists vs= sequential arrays vs associative arrays, for various element counts. (Did that already in another language (freepascal), to know what kind of da= ta structures were suited for symbol tables representing the content of rec= ord-like objects, which number of entries is typically small since hand-wri= tten by the programmer: sophisticated structures like associative arrays an= d tries started to perform better than plain sequences for counts >> 100.)in "(*symbol).name". Is this just normal (for disambiguation)?1. To please the compiler, I had to wrap dereferencing in parens, like =ointer: is there implicit dereferencing of pointers to structs? If yes, doe= s this also apply to pointers to arrays (for information, this what Oberon = does).2. Just noticed the compiler accepts "symbol.name", while symbol is a p==20 Generally the field dereferencing doesn't require the "(*symbol).name", i=n D you use "symbol.name".Pointers to arrays are possible, but quite uncommon in D.Sure, there are builtin dynamic arrays :-) I'll check whether manually pointed arrays also silently dereferencing (on = element access, on attribute access)?he linker produced a rather big amount of error text without any hint to th= e actual issue. Maybe dmd could cope with that before calling gcc?And a note: had forgotten to add an empty main(), just for compiling: t==20 I agree, I have bug report 4680 open on something similar: http://d.puremagic.com/issues/show_bug.cgi?id=3D4680Good.xample (I have few practice of C, and none of C++); the bits of tutorials I= found are too light or just started (toc points to empty pages). Is there = anywhere online a kind of D programming guide, even not polished or possibl= y unfinished (I know about the book; maybe I'll order it, but in meantime..= .).Finally: the reference is rather harsh for me, esp there are very few e==20 The D2 documentation isn't abundant yet :-)I'll do what I can on one of the already started wikibooks about D if I fin= d energy for that...Bye, bearophileThanks again, Denis -- -- -- -- -- -- -- vit esse estrany =E2=98=A3 spir.wikidot.com
Oct 14 2010
spir:(Hope you don't mind if I send other bits of code to be improved that way?)Feel free to show them, if I am busy other people may give you an answer. The worst that may happen is that no one answers you.Right. I think at keeping explicit defaults like "int element = 0" for documentation.Not putting a value, unless it's different from the standard initializator, is a very common idiom in D. It's easy to remember the inits: zero, empty string, NaN, null, invalid Unicode chars.If I ever write a lib for public use, I'll follow such styling guidelines ;-)The D style: http://www.digitalmars.com/d/2.0/dstyle.htmlWouldn't have ever thought that the "stepping" statement of a for loop can be something else as incrementation.This is a kind of incrementation: symbol = symbol.next; In C-derived languages this line of code: symbol = symbol + 5; May be written: symbol += 5; In the same way you may think of this (this is not D syntax): symbol .= next; As a compact version of: symbol = symbol.next;Right, guess you mean while(symbol != null)?Right. But some people don't like that.I need to explore this further (what's the actual purpose of "auto").It just asks the compiler to use the default type, it performs a bit of local type inferencing.For curiosity, I intend to benchmark lists vs sequential arrays vs associative arrays, for various element counts.Good, it's a way to understand the language better. In the lists vs dynamic array I suggest you to also take a look at the produced (dis)assembly.to know what kind of data structures were suited for symbol tables representing the content of record-like objects, which number of entries is typically small since hand-written by the programmer: sophisticated structures like associative arrays and tries started to perform better than plain sequences for counts >> 100.)<D dynamic arrays are not bad, but they are not very efficient, so a sequential scan in a small array of integer numbers is faster than an hash search. You may also try a "perfect hash", for your purpose. Around you may find C code (that's easy to translate to D) to create a perfect hash out of a sequence of strings. A binary search in an array of strings-int pairs is an easy option too. If your symbol are names are short you may also put your string+int pairs in a single flat data structure (even keeping a fixed length for each one of them), to increase CPU cache locality a bit, something like: struct Pair { char[10] name; int element; } Pair[20] data; In C/C++/D languages usually there are *many* complicated ways to speed up code :-) You generally want to use them only in the spots where the profiler tells you you need performance. The profiler is used with the DMD -profile switch. It's also good if you learn D to start using unittests and design by contract from the beginning. They help a lot avoid bugs. And the more hairy (pointers, etc) your code is, the more useful they are. Bye, bearophile
Oct 14 2010
D dynamic arrays are not bad, but they are not very efficient,I meant associative array, sorry.
Oct 14 2010
On 10/14/10, bearophile <bearophileHUGS lycos.com> wrote:Generally the field dereferencing doesn't require the "(*symbol).name", in D you use "symbol.name". Pointers to arrays are possible, but quite uncommon in D.I'm not sure, but I think function pointers (the C syntax ones, not variables declared with function/delegate) still need parenthesis for dereferencing? IIRC I was getting back some weird errors a few days ago when I was trying it out. I might be wrong though..
Oct 14 2010