Re: Ranges
Hi Jonathan, Thank you very much your in depth answer! It should indeed goto a faq somewhere it think. I did now about the codepoint/unit stuff but had no idea that ranges of char are handled using dchar internally. This makes sense but is an easy pitfall for newcomers trying to use std.{algoritm,array,ranges} for char[]. Thanks Jonas On 13/03/11 01.05, Jonathan M Davis wrote: On Saturday 12 March 2011 14:02:00 Jonas Drewsen wrote: Hi, I'm working a bit with ranges atm. but there are definitely some things that are not clear to me yet. Can anyone tell me why the char arrays cannot be copied but the int arrays can? import std.stdio; import std.algorithm; void main(string[] args) { // This works int[] a1 = [1,2,3,4]; int[] a2 = [5,6,7,8]; copy(a1, a2); // This does not! char[] a3 = ['1','2','3','4']; char[] a4 = ['5','6','7','8']; copy(a3, a4); } Error message: test2.d(13): Error: template std.algorithm.copy(Range1,Range2) if (isInputRange!(Range1)&& isOutputRange!(Range2,ElementType!(Range1))) does not match any function template declaration test2.d(13): Error: template std.algorithm.copy(Range1,Range2) if (isInputRange!(Range1)&& isOutputRange!(Range2,ElementType!(Range1))) cannot deduce template function from argument types !()(char[],char[]) Character arrays / strings are not exactly normal. And there's a very good reason for it: unicode. In unicode, a character is generally a single code point (there are also graphemes which involve combining code points to add accents and superscripts and whatnot to create a single character, but we'll ignore that in this discussion - it's complicated enough as it is). Depending on the encoding, that code point may be made up of one - or more - code units. UTF-8 uses 8 bit code units. UTF-16 uses 16 bit code units. And UTF-32 uses 32-bit code units. char is a UTF-8 code unit. wchar is a UTF-16 code unit. dchar is a UTF-32 code unit. UTF-32 is the _only_ one of those three which _always_ has one code unit per code point. With an array of integers you can index it and slice it and be sure that everything that you're doing is valid. If you look at a single element, you know that it's a valid int. If you slice it, you know that every int in there is valid. If you're dealing with a dstring or dchar[], then the same still holds. A dstring or dchar[] is an array of UTF-32 code units. Every code point is a single code unit, so every element in the array is a valid code point. You can take an arbitrary element in that array and know that it's a valid code point. You can slice it wherever you want and you still have a valid dstrin g or dchar[]. The same does _not_ hold for char[] and wchar[]. char[] and wchar[] are arrays of UTF-8 and UTF-16 code units respectively. In both of those encodings, multiple code units are required to create a single code point. So, for instance, a code point could have 4 code units. That means that _4_ elements of that char[] make up a _single_ code point. You'd need _all_ 4 of those elements to create a single, valid character. So, you _can't_ just take an arbitrary element in a char[] or wchar[] and expect it to be valid. You _can't_ just slice it anywhere. The resulting array stands a good chance of being invalid. You have to slice on code point boundaries - otherwise you could slice characters in hald and end up with an invalid string. So, unlike other arrays, it just doesn't work to treat char[] and wchar[] as random access ranges of their element type. What the programmer cares about is characters - dchars - not chars or wchars. So, the way this is handled is that char[], wchar[], and dchar[] are all treated as ranges of dchar. In the case of dchar[], this is nothing special. You can index it and slice it as normal. So, it is a random access range.. However, in the case of char[] and wchar[], that means that when you're iterating over them that you're not dealing with a single element of the array at a time. front returns a dchar, and popFront() pops off however many elements made up front. It's like with foreach. If you iterate a char[] with auto or char, then each individual element is given foreach(c; myStr) {} But if you iterate over with dchar, then each code point is given as a dchar: foreach(dchar c; myStr) {} If you were to try and iterate over a char[] by char, then you would be looking at code units rather than code points which is _rarely_ what you want. If you're dealing with anything other than pure ASCII, you _will_ have bugs if you do that. You're supposed to use dchar with foreach and character arrays. That way, each value you process is a valid character. Ranges do the same, only you don't give them an iteration type, so they're _always_ iterating over dchar. So, when you're using a range of char[] or wchar[], you're really using a range of dchar. These ranges are bi-directional. They can't be sliced, and they can't be indexed (since doing so wou
Re: .di header imports with DLL symbols fails to link
On 3/12/2011 11:39 PM, Bekenn wrote: On 3/12/2011 7:02 PM, Andrej Mitrovic wrote: My commands to compile were: dmd -ofmydll.dll mydll.d dmd -o- -Hdinclude mydll.d dmd driver.d mydll.lib -I%cd%\include Thanks. I've tried several things, but can't get the _D5mydll12__ModuleInfoZ symbol to show up at all. The behavior is the same with and without a .def file (I tried a few versions). I even went back to http://www.digitalmars.com/d/2.0/dll.html and copied everything in the "D code calling D code in DLLs" section verbatim. After fixing a few compilation errors (the web page's version of concat needs its arguments qualified with "in"), I ended up with the exact same problem you're experiencing. I'd definitely call this a bug. Probably unrelated, but this same issue showed up in the GDC backend. Apparently, the compiler tried to be smart about exporting ModuleInfo only for those modules that needed it. The fix was to always export it regardless.
Re: .di header imports with DLL symbols fails to link
On 3/12/2011 7:02 PM, Andrej Mitrovic wrote: My commands to compile were: dmd -ofmydll.dll mydll.d dmd -o- -Hdinclude mydll.d dmd driver.d mydll.lib -I%cd%\include Thanks. I've tried several things, but can't get the _D5mydll12__ModuleInfoZ symbol to show up at all. The behavior is the same with and without a .def file (I tried a few versions). I even went back to http://www.digitalmars.com/d/2.0/dll.html and copied everything in the "D code calling D code in DLLs" section verbatim. After fixing a few compilation errors (the web page's version of concat needs its arguments qualified with "in"), I ended up with the exact same problem you're experiencing. I'd definitely call this a bug.
Re: .di header imports with DLL symbols fails to link
My commands to compile were: dmd -ofmydll.dll mydll.d dmd -o- -Hdinclude mydll.d dmd driver.d mydll.lib -I%cd%\include
Re: .di header imports with DLL symbols fails to link
Actually passing that .di file compiles it in statically, and the exe ends up not needing the DLL. It's a bit too late for me to thinker with the linker, I'll have a clearer head tomorrow.
Re: .di header imports with DLL symbols fails to link
On 3/12/2011 9:15 PM, Bekenn wrote: On 3/12/2011 5:24 PM, Andrej Mitrovic wrote: driver.obj(driver) Error 42: Symbol Undefined _D5mydll12__ModuleInfoZ --- errorlevel 1 Your dll is exporting a different symbol: _D5mydll3fooFiZi Do you have the .def file and the command line used to build the DLL? I believe _D5mydll12__ModuleInfoZ is supposed to be exported by the compiler. It contains static constructor and unittest information used by the runtime to initialize it.
Re: .di header imports with DLL symbols fails to link
On 3/12/2011 5:24 PM, Andrej Mitrovic wrote: driver.obj(driver) Error 42: Symbol Undefined _D5mydll12__ModuleInfoZ --- errorlevel 1 Your dll is exporting a different symbol: _D5mydll3fooFiZi Do you have the .def file and the command line used to build the DLL?
Re: Ranges
What Jonathan said really needs to be put up on the D website, maybe under the articles section. Heck, I'd just put a link to that recent UTF thread on the website, it's really informative (the one on UTF and meaning of glyphs, etc). And UTF will only get more important, just like multicore. Speaking of which, a description on ranges should be put up there as well. There's that article Andrei once wrote, but we should put it on the D site and discuss D's implementation of ranges in more detail. And by 'we' I mean someone who's well versed in ranges. :p
.di header imports with DLL symbols fails to link
On Windows, x86. http://dl.dropbox.com/u/9218759/DLL_Imports.zip fail_build.bat runs: dmd driver.d mydll.lib -I%cd%\include\ but linking fails: driver.obj(driver) Error 42: Symbol Undefined _D5mydll12__ModuleInfoZ --- errorlevel 1 work_build.bat runs: dmd driver.d mydll.lib %cd%\include\mydll.di and this succeeds. So passing the .di file explicitly works, but via the import switch it does not. Here's a non-DLL example which works fine when using header files and an import switch: http://dl.dropbox.com/u/9218759/importsWorkUsually.zip So unless I'm missing something this looks like a linker bug?
Re: Ranges
On Saturday 12 March 2011 16:11:20 Bekenn wrote: > On 3/12/2011 2:02 PM, Jonas Drewsen wrote: > > Error message: > > > > test2.d(13): Error: template std.algorithm.copy(Range1,Range2) if > > (isInputRange!(Range1) && isOutputRange!(Range2,ElementType!(Range1))) > > does not match any function template declaration > > > > test2.d(13): Error: template std.algorithm.copy(Range1,Range2) if > > (isInputRange!(Range1) && isOutputRange!(Range2,ElementType!(Range1))) > > cannot deduce template function from argument types !()(char[],char[]) > > I haven't checked (could be completely off here), but I don't think that > char[] counts as an input range; you would normally want to use dchar > instead. Char[] _does_ count as input range (of dchar). It just doesn't count as an _output_ range (since it doesn't really hold dchar). - Jonathan M Davis
Re: Ranges
On Saturday 12 March 2011 16:05:37 Jonathan M Davis wrote: > You could open an > enhancement request for copy to treat char[] and wchar[] as arrays if > _both_ of the arguments are of the same type. Actually, on reflection, I'd have to say that there's not much point to that. If you really want to copy on array to another (rather than a range), just use the array copy syntax: void main() { auto i = [1, 2, 3, 4]; auto j = [3, 4, 5, 6]; assert(i == [1, 2, 3, 4]); assert(j == [3, 4, 5, 6]); i[] = j[]; assert(i == [3, 4, 5, 6]); assert(j == [3, 4, 5, 6]); } copy is of benefit, because it works on generic ranges, not for copying arrays (arrays already allow you to do that quite nicely), so if all you're looking at copying is arrays, then just use the array copy syntax. - Jonathan M Davis
Re: Ranges
Or, better yet, just read Jonathan's post.
Re: Ranges
On 3/12/2011 2:02 PM, Jonas Drewsen wrote: Error message: test2.d(13): Error: template std.algorithm.copy(Range1,Range2) if (isInputRange!(Range1) && isOutputRange!(Range2,ElementType!(Range1))) does not match any function template declaration test2.d(13): Error: template std.algorithm.copy(Range1,Range2) if (isInputRange!(Range1) && isOutputRange!(Range2,ElementType!(Range1))) cannot deduce template function from argument types !()(char[],char[]) I haven't checked (could be completely off here), but I don't think that char[] counts as an input range; you would normally want to use dchar instead.
Re: Points and Vectors in 3D
On 3/12/2011 2:20 PM, Simon wrote: I've done lots of 3d over the years and used quite a lot of different libraries and I've come to prefer code that makes a distinction between points and vectors. Agreed. This has some nice benefits with operator overloading, as well: vec v = ...; pt p = ...; auto p2 = p + v;// p2 is pt auto p3 = p + p2; // error auto v2 = v + v;// v2 is vec ...and with properties: p.x = 5;// p is pt, sets p._vals[0] v.dx = 3; // v is vec, sets v._vals[0]
Re: Ranges
On Saturday 12 March 2011 14:02:00 Jonas Drewsen wrote: > Hi, > > I'm working a bit with ranges atm. but there are definitely some > things that are not clear to me yet. Can anyone tell me why the char > arrays cannot be copied but the int arrays can? > > import std.stdio; > import std.algorithm; > > void main(string[] args) { > >// This works >int[] a1 = [1,2,3,4]; >int[] a2 = [5,6,7,8]; >copy(a1, a2); > >// This does not! >char[] a3 = ['1','2','3','4']; >char[] a4 = ['5','6','7','8']; >copy(a3, a4); > > } > > Error message: > > test2.d(13): Error: template std.algorithm.copy(Range1,Range2) if > (isInputRange!(Range1) && isOutputRange!(Range2,ElementType!(Range1))) > does not match any function template declaration > > test2.d(13): Error: template std.algorithm.copy(Range1,Range2) if > (isInputRange!(Range1) && isOutputRange!(Range2,ElementType!(Range1))) > cannot deduce template function from argument types !()(char[],char[]) Character arrays / strings are not exactly normal. And there's a very good reason for it: unicode. In unicode, a character is generally a single code point (there are also graphemes which involve combining code points to add accents and superscripts and whatnot to create a single character, but we'll ignore that in this discussion - it's complicated enough as it is). Depending on the encoding, that code point may be made up of one - or more - code units. UTF-8 uses 8 bit code units. UTF-16 uses 16 bit code units. And UTF-32 uses 32-bit code units. char is a UTF-8 code unit. wchar is a UTF-16 code unit. dchar is a UTF-32 code unit. UTF-32 is the _only_ one of those three which _always_ has one code unit per code point. With an array of integers you can index it and slice it and be sure that everything that you're doing is valid. If you look at a single element, you know that it's a valid int. If you slice it, you know that every int in there is valid. If you're dealing with a dstring or dchar[], then the same still holds. A dstring or dchar[] is an array of UTF-32 code units. Every code point is a single code unit, so every element in the array is a valid code point. You can take an arbitrary element in that array and know that it's a valid code point. You can slice it wherever you want and you still have a valid dstrin g or dchar[]. The same does _not_ hold for char[] and wchar[]. char[] and wchar[] are arrays of UTF-8 and UTF-16 code units respectively. In both of those encodings, multiple code units are required to create a single code point. So, for instance, a code point could have 4 code units. That means that _4_ elements of that char[] make up a _single_ code point. You'd need _all_ 4 of those elements to create a single, valid character. So, you _can't_ just take an arbitrary element in a char[] or wchar[] and expect it to be valid. You _can't_ just slice it anywhere. The resulting array stands a good chance of being invalid. You have to slice on code point boundaries - otherwise you could slice characters in hald and end up with an invalid string. So, unlike other arrays, it just doesn't work to treat char[] and wchar[] as random access ranges of their element type. What the programmer cares about is characters - dchars - not chars or wchars. So, the way this is handled is that char[], wchar[], and dchar[] are all treated as ranges of dchar. In the case of dchar[], this is nothing special. You can index it and slice it as normal. So, it is a random access range.. However, in the case of char[] and wchar[], that means that when you're iterating over them that you're not dealing with a single element of the array at a time. front returns a dchar, and popFront() pops off however many elements made up front. It's like with foreach. If you iterate a char[] with auto or char, then each individual element is given foreach(c; myStr) {} But if you iterate over with dchar, then each code point is given as a dchar: foreach(dchar c; myStr) {} If you were to try and iterate over a char[] by char, then you would be looking at code units rather than code points which is _rarely_ what you want. If you're dealing with anything other than pure ASCII, you _will_ have bugs if you do that. You're supposed to use dchar with foreach and character arrays. That way, each value you process is a valid character. Ranges do the same, only you don't give them an iteration type, so they're _always_ iterating over dchar. So, when you're using a range of char[] or wchar[], you're really using a range of dchar. These ranges are bi-directional. They can't be sliced, and they can't be indexed (since doing so would likely be invalid). This generally works very well. It's exactly what you want in most cases. The problem is that that means that the range that you're iterating over is effectively of a different type than the original char[] or wchar[]. You can't just take two ranges of dchar of the same
Re: struct construct with array
On 03/12/2011 02:52 PM, Ali Çehreli wrote: On 03/12/2011 10:42 AM, Caligo wrote: struct Test{ public double[3] ar_; this(double[3] ar){ this.ar_ = ar; } } void main(){ double[3] v1 = [1.0, 2.0, 3.0]; double[3] v2 = [2.0, 3.0, 4.0]; auto t1 = Test(v1[0..$] + v2[0..$]); // error } I want to add those two arrays and call the constructor in one line, but I'm getting an error. Any ideas? Even a simpler code doesn't work: double[3] v1 = [1.0, 2.0, 3.0]; double[3] v2 = [2.0, 3.0, 4.0]; auto result = v1[0..$] + v2[0..$]; Error: Array operation v1[0LU..__dollar] + v2[0LU..__dollar] not implemented The following doesn't work either: auto result = v1[] + v2[]; auto result = v1 + v2; dmd does not implement those features yet. Ali I see from the other posts that the problem has something to do with auto. This works: double[3] v3 = v1[] + v2[]; Ali
Re: struct construct with array
On 03/12/2011 10:42 AM, Caligo wrote: struct Test{ public double[3] ar_; this(double[3] ar){ this.ar_ = ar; } } void main(){ double[3] v1 = [1.0, 2.0, 3.0]; double[3] v2 = [2.0, 3.0, 4.0]; auto t1 = Test(v1[0..$] + v2[0..$]); // error } I want to add those two arrays and call the constructor in one line, but I'm getting an error. Any ideas? Even a simpler code doesn't work: double[3] v1 = [1.0, 2.0, 3.0]; double[3] v2 = [2.0, 3.0, 4.0]; auto result = v1[0..$] + v2[0..$]; Error: Array operation v1[0LU..__dollar] + v2[0LU..__dollar] not implemented The following doesn't work either: auto result = v1[] + v2[]; auto result = v1 + v2; dmd does not implement those features yet. Ali
Re: Points and Vectors in 3D
On 12/03/2011 20:51, Caligo wrote: Given everything that D offers, what would be the best way to implement a Point and a Vector type? The same (x, y, z) can be used to represent vectors, but a point represents a position, whereas a vector represents a direction. So, would you define two different structs for each? or define and implement an interface? a fixed array or POD members? I've done lots of 3d over the years and used quite a lot of different libraries and I've come to prefer code that makes a distinction between points and vectors. Makes code easier to read and more type safe, though it's a bit more inconvenient when you need to mix things up. I use: struct pt { float[3] _vals; } struct vec { float[3] _vals; } Using the float[3] allows you to use vector ops: pt p0; vec v; p0._vals[] += v._vals[]; You don't want an interface; you don't get anything more value type than points & vectors. In a modern 3d models you could be dealing with a 1/2 million vertices. -- My enormous talent is exceeded only by my outrageous laziness. http://www.ssTk.co.uk
Ranges
Hi, I'm working a bit with ranges atm. but there are definitely some things that are not clear to me yet. Can anyone tell me why the char arrays cannot be copied but the int arrays can? import std.stdio; import std.algorithm; void main(string[] args) { // This works int[] a1 = [1,2,3,4]; int[] a2 = [5,6,7,8]; copy(a1, a2); // This does not! char[] a3 = ['1','2','3','4']; char[] a4 = ['5','6','7','8']; copy(a3, a4); } Error message: test2.d(13): Error: template std.algorithm.copy(Range1,Range2) if (isInputRange!(Range1) && isOutputRange!(Range2,ElementType!(Range1))) does not match any function template declaration test2.d(13): Error: template std.algorithm.copy(Range1,Range2) if (isInputRange!(Range1) && isOutputRange!(Range2,ElementType!(Range1))) cannot deduce template function from argument types !()(char[],char[]) Thanks, Jonas
Points and Vectors in 3D
Given everything that D offers, what would be the best way to implement a Point and a Vector type? The same (x, y, z) can be used to represent vectors, but a point represents a position, whereas a vector represents a direction. So, would you define two different structs for each? or define and implement an interface? a fixed array or POD members?
Re: struct construct with array
On Sat, Mar 12, 2011 at 1:02 PM, Andrej Mitrovic wrote: > The best thing I can think of is introducing a temp variable: > > void main(){ >double[3] v1 = [1.0, 2.0, 3.0]; >double[3] v2 = [2.0, 3.0, 4.0]; > > double[3] v3 = v1[] + v2[]; >auto t1 = Test(v3); > } > Thanks, but I want to do it in one line, without creating a temporary.
Re: struct construct with array
The best thing I can think of is introducing a temp variable: void main(){ double[3] v1 = [1.0, 2.0, 3.0]; double[3] v2 = [2.0, 3.0, 4.0]; double[3] v3 = v1[] + v2[]; auto t1 = Test(v3); }
struct construct with array
struct Test{ public double[3] ar_; this(double[3] ar){ this.ar_ = ar; } } void main(){ double[3] v1 = [1.0, 2.0, 3.0]; double[3] v2 = [2.0, 3.0, 4.0]; auto t1 = Test(v1[0..$] + v2[0..$]); // error } I want to add those two arrays and call the constructor in one line, but I'm getting an error. Any ideas?
Re: Fibonacci with ranges
On Saturday 12 March 2011 02:48:19 Russel Winder wrote: > Jonathan, > > On Sat, 2011-03-12 at 10:31 +, Russel Winder wrote: > [ . . . ] > > > > What's happening is that the parameter that you're passing n to for > > > recurrence is size_t. And on 32-bit systems, size_t is uint, so > > > passing n - which is long - to recurrence would be a narrowing > > > conversion, which requires a cast. The correct thing to do would be > > > make n a size_t. The other thing that you'd need to do is change > > > declarative to return auto, since take returns a range, _not_ a long. > > To analyse this a bit more I temporarily deconstructed the expression: > > long declarative ( immutable long n ) { > auto r = recurrence ! ( "a[n-1] + a[n-2]" ) ( 0L , 1L ) ; > auto t = take ( r , cast ( size_t ) ( n ) ) ; > return t [ n ] ; > //return ( take ( recurrence ! ( "a[n-1] + a[n-2]" ) ( 0L , 1L ) > , cast ( size_t ) ( n ) ) ) [ n ] ; } > > So with the cast it compiles fine -- though it still seems to me to be > beyond the point of comprehension as to why an applications programmer > has to manually cast a long to a size_t. However the indexing of the > range fails: Um. Because it's a narrowing conversion on 32-bit machines. What else should it be doing? If it allowed the narrowing conversion without a cast, then you'd run into problems where you were losing precision without realizing it which would cause plenty of other entertaining bugs. Most newer languages require casts for narrowing conversions. > fibonacci_d2.d(17): Error: no [] operator overload for type > Take!(Recurrence!(fun,long,2u)) > > Which elicits the response: for f sake, I'm just copying the > example from the manual. > > OK, so I am grumpy this morning, but that doesn't affect the fact that > there appears to be a disconnect between documentation and what actually > works. take will only return a sliceable range if the range that you give it is sliceable. recurrence does not return a sliceable range, so take used an the result of recurrence doesn't return a sliceable range. The documentation for take is completely correct. It's just that it only has an array in its example, not a range which _isn't_ sliceable, so the one example that it does have involves a sliceable range. - Jonathan M Davis
Re: Fibonacci with ranges
Jonathan, On Sat, 2011-03-12 at 10:31 +, Russel Winder wrote: [ . . . ] > > What's happening is that the parameter that you're passing n to for > > recurrence > > is size_t. And on 32-bit systems, size_t is uint, so passing n - which is > > long - > > to recurrence would be a narrowing conversion, which requires a cast. The > > correct thing to do would be make n a size_t. The other thing that you'd > > need to > > do is change declarative to return auto, since take returns a range, _not_ > > a > > long. To analyse this a bit more I temporarily deconstructed the expression: long declarative ( immutable long n ) { auto r = recurrence ! ( "a[n-1] + a[n-2]" ) ( 0L , 1L ) ; auto t = take ( r , cast ( size_t ) ( n ) ) ; return t [ n ] ; //return ( take ( recurrence ! ( "a[n-1] + a[n-2]" ) ( 0L , 1L ) , cast ( size_t ) ( n ) ) ) [ n ] ; } So with the cast it compiles fine -- though it still seems to me to be beyond the point of comprehension as to why an applications programmer has to manually cast a long to a size_t. However the indexing of the range fails: fibonacci_d2.d(17): Error: no [] operator overload for type Take!(Recurrence!(fun,long,2u)) Which elicits the response: for f sake, I'm just copying the example from the manual. OK, so I am grumpy this morning, but that doesn't affect the fact that there appears to be a disconnect between documentation and what actually works. -- Russel. = Dr Russel Winder t: +44 20 7585 2200 voip: sip:russel.win...@ekiga.net 41 Buckmaster Roadm: +44 7770 465 077 xmpp: rus...@russel.org.uk London SW11 1EN, UK w: www.russel.org.uk skype: russel_winder signature.asc Description: This is a digitally signed message part
Re: Fibonacci with ranges
On Saturday 12 March 2011 02:31:20 Russel Winder wrote: > Jonathan, > > Thanks for the info, very helpful. One point though: > > On Sat, 2011-03-12 at 01:56 -0800, Jonathan M Davis wrote: > [ . . . ] > > > What's happening is that the parameter that you're passing n to for > > recurrence is size_t. And on 32-bit systems, size_t is uint, so passing > > n - which is long - to recurrence would be a narrowing conversion, which > > requires a cast. The correct thing to do would be make n a size_t. The > > other thing that you'd need to do is change declarative to return auto, > > since take returns a range, _not_ a long. > > It seems that D is falling into the same bear trap as C++ (and C?) > descended into long ago. When a programmer want an int or a long, they > actually have to decide whether they need a size_t. To be honest this > is a simple WTF!!! > > Go really has this right. int does not exist, neither does long. > int32, int64 -- no ambiguity. Why C++ and D have to continue with the > pretence of platform independent types when they are far from platform > independent seems counter-productive. > > > > Thanks for the pointer about the take, I need to select just the last > entry in the range and return that. > > > In any case, it _would_ be nice if the compiler gave a more informative > > message about _why_ the template failed to instantiate - especially > > since it's _not_ the template constraint which is the problem - but > > unfortunately, the compiler just isn't that smart about template > > instantiation errors. > > C++ is bad enough, if D cannot improve on it . . . :-(( size_t pretty much needs to be platform-dependent unless you want to restrict arrays to uint.size as their maximum size. And that really isn't acceptable for a systems language ( there are probably other reasons why size_t is need - that's just the most obvious). size_t is used anywhere that an index would be used. take is one of those places. Besides indices though, size_t isn't something that you're going to run into all that often in Phobos. Regardless, size_t has _nothing_ to do with your problem here. The problem is that you're trying to pass a long to a uint parameter. That problem would exist even if uint was used directly instead of size_t. It's a narrowing conversion, and those require casts. I expect that Go would have exactly the same problem with int32 and int64 - unless Go allows narrowing conversions without casts like C and C++ do, which causes a whole host of other problems. So, while you may not like size_t, it really isn't your problem here. Now, the error on the failed template instantiation could certainly use some improvement, but that's completely separate from the type issue. That's just it doing poorly at reporting the error caused by the type issue. D certainly could use further improvement with regards to template errors, but on the whole, D's templates are _far_ better than C++'s. - Jonathan M Davis
Re: Read file/stream
== Auszug aus Stewart Gordon (smjg_1...@yahoo.com)'s Artikel > On 11/03/2011 18:46, Steven Schveighoffer wrote: > > > I am not sure what facilities Phobos provides for reading/writing integers in network > > order (i.e. Big Endian), but I'm sure there's something. > http://www.digitalmars.com/d/1.0/phobos/std_stream.html > EndianStream > I haven't experimented with it. And I don't expect it to handle structs well. > Alternatively, you could use some simple code like > > version (BigEndian) { > uint bigEndian(uint value) { > return value; > } > } > version (LittleEndian) { > uint bigEndian(uint value) { > return value << 24 >| (value & 0xFF00) << 8 >| (value & 0x00FF) >> 8 >| value >> 24; > } > } > > though you would have to remember to call it for each file I/O operation that relies on > it. If you use a struct, you could put a method in it to call bigEndian on the members of > relevance. > Stewart. That's working - thanks for all replies!
Re: Fibonacci with ranges
On Sat, 2011-03-12 at 02:15 -0800, Ali Çehreli wrote: [ . . . ] > void main() > { > long[] data = [ 0, 1, 1, 2, 3, 5, 8 ]; > > foreach (n; 0 .. data.length) { > assert(equal(declarative(n), data[0..n])); > } > } In fact the driver is: unittest { immutable data = [ [ 0 , 0 ] , [ 1 , 1 ] , [ 2 , 1 ] , [ 3 , 2 ] , [ 4 , 3 ] , [ 5 , 5 ] , [ 6 , 8 ] , [ 7 , 13 ] , [ 8 , 21 ] , [ 9 , 34 ] , [ 10 , 55 ] , [ 11 , 89 ] , [ 12 , 144 ] , [ 13 , 233 ] , ] ; foreach ( item ; data ) { assert ( iterative ( item[0] ) == item[1] ) ; } foreach ( item ; data ) { assert ( declarative ( item[0] ) == item[1] ) ; } } so I need to index the take-n list to return the last value. This of course brings up the question of the signature of any factorial function. Without a real use case it is a rhetorical question. What is nice though is that there could be a neat way of generating a memoized, i.e. cached, lazy list. -- Russel. = Dr Russel Winder t: +44 20 7585 2200 voip: sip:russel.win...@ekiga.net 41 Buckmaster Roadm: +44 7770 465 077 xmpp: rus...@russel.org.uk London SW11 1EN, UK w: www.russel.org.uk skype: russel_winder signature.asc Description: This is a digitally signed message part
Re: Fibonacci with ranges
Jonathan, Thanks for the info, very helpful. One point though: On Sat, 2011-03-12 at 01:56 -0800, Jonathan M Davis wrote: [ . . . ] > What's happening is that the parameter that you're passing n to for > recurrence > is size_t. And on 32-bit systems, size_t is uint, so passing n - which is > long - > to recurrence would be a narrowing conversion, which requires a cast. The > correct thing to do would be make n a size_t. The other thing that you'd need > to > do is change declarative to return auto, since take returns a range, _not_ a > long. It seems that D is falling into the same bear trap as C++ (and C?) descended into long ago. When a programmer want an int or a long, they actually have to decide whether they need a size_t. To be honest this is a simple WTF!!! Go really has this right. int does not exist, neither does long. int32, int64 -- no ambiguity. Why C++ and D have to continue with the pretence of platform independent types when they are far from platform independent seems counter-productive. Thanks for the pointer about the take, I need to select just the last entry in the range and return that. > In any case, it _would_ be nice if the compiler gave a more informative > message > about _why_ the template failed to instantiate - especially since it's _not_ > the > template constraint which is the problem - but unfortunately, the compiler > just > isn't that smart about template instantiation errors. C++ is bad enough, if D cannot improve on it . . . :-(( -- Russel. = Dr Russel Winder t: +44 20 7585 2200 voip: sip:russel.win...@ekiga.net 41 Buckmaster Roadm: +44 7770 465 077 xmpp: rus...@russel.org.uk London SW11 1EN, UK w: www.russel.org.uk skype: russel_winder signature.asc Description: This is a digitally signed message part
Re: Fibonacci with ranges
On 03/12/2011 01:33 AM, Russel Winder wrote: > On Fri, 2011-03-11 at 18:46 -0500, Jesse Phillips wrote: >> Without testing: foreach (f; take(recurrence!("a[n-1] + a[n-2]")(0UL, 1UL), 50)) >> >> teo Wrote: >> >>> Just curious: How can I get ulong here? >>> >>> foreach (f; take(recurrence!("a[n-1] + a[n-2]")(0, 1), 50)) >>> { >>>writeln(f); >>> } >> > > Interestingly, or not, the code: > > long declarative ( immutable long n ) { >return take ( recurrence ! ( "a[n-1] + a[n-2]" ) ( 0L , 1L ) , n ) ; > } take returns a lazy range which can't be returned as a single long. Reading your other post, I think this may be what you wanted to see: import std.range; import std.algorithm; auto declarative(immutable long n) { return take(recurrence!("a[n-1] + a[n-2]")(0L, 1L), n); } void main() { long[] data = [ 0, 1, 1, 2, 3, 5, 8 ]; foreach (n; 0 .. data.length) { assert(equal(declarative(n), data[0..n])); } } Ali
Re: Fibonacci with ranges
On Saturday 12 March 2011 01:33:34 Russel Winder wrote: > On Fri, 2011-03-11 at 18:46 -0500, Jesse Phillips wrote: > > Without testing: foreach (f; take(recurrence!("a[n-1] + a[n-2]")(0UL, > > 1UL), 50)) > > > > teo Wrote: > > > Just curious: How can I get ulong here? > > > > > > foreach (f; take(recurrence!("a[n-1] + a[n-2]")(0, 1), 50)) > > > { > > > > > > writeln(f); > > > > > > } > > Interestingly, or not, the code: > > long declarative ( immutable long n ) { > return take ( recurrence ! ( "a[n-1] + a[n-2]" ) ( 0L , 1L ) , n ) ; > } > > results in the return statement delivering: > > rdmd --main -unittest fibonacci_d2.d > fibonacci_d2.d(15): Error: template std.range.take(R) if > (isInputRange!(Unqual!(R)) && !isSafelySlicable!(Unqual!(R)) && > !is(Unqual!(R) T == Take!(T))) does not match any function template > declaration fibonacci_d2.d(15): Error: template std.range.take(R) if > (isInputRange!(Unqual!(R)) && !isSafelySlicable!(Unqual!(R)) && > !is(Unqual!(R) T == Take!(T))) cannot deduce template function from > argument types !()(Recurrence!(fun,long,2u),immutable(long)) > > which seems deeply impenetrable for mere mortals. LOL. Maybe I've been dealing with template code for too long, because that seems perfectly clear to me. Though I can certainly understand why it wouldn't be. Incidentally, isSafelySlicable will be going away (essentially it's checking that the range isn't some type of char[] or wchar[], and Andrei's just going to make it so that isSliceable is false for them). All that template constraint is checking for is that the range is an input range which can't be sliced and isn't already a range returned from take. If a range _is_ sliceable, then take just returns the same range type. However, I don't think that constraint is necessarily all that useful in this case. It's just that it's the first version of the template, so that's the way that gets displayed when the compiler can't instantiate any of the versions of the template with the given arguments. What's happening is that the parameter that you're passing n to for recurrence is size_t. And on 32-bit systems, size_t is uint, so passing n - which is long - to recurrence would be a narrowing conversion, which requires a cast. The correct thing to do would be make n a size_t. The other thing that you'd need to do is change declarative to return auto, since take returns a range, _not_ a long. In any case, it _would_ be nice if the compiler gave a more informative message about _why_ the template failed to instantiate - especially since it's _not_ the template constraint which is the problem - but unfortunately, the compiler just isn't that smart about template instantiation errors. - Jonathan M Davis
Re: Fibonacci with ranges
On Sat, 2011-03-12 at 09:33 +, Russel Winder wrote: [ . . . ] > Interestingly, or not, the code: > > long declarative ( immutable long n ) { > return take ( recurrence ! ( "a[n-1] + a[n-2]" ) ( 0L , 1L ) , n ) ; > } > > results in the return statement delivering: > > rdmd --main -unittest fibonacci_d2.d > fibonacci_d2.d(15): Error: template std.range.take(R) if > (isInputRange!(Unqual!(R)) && !isSafelySlicable!(Unqual!(R)) && > !is(Unqual!(R) T == Take!(T))) does not match any function template > declaration > fibonacci_d2.d(15): Error: template std.range.take(R) if > (isInputRange!(Unqual!(R)) && !isSafelySlicable!(Unqual!(R)) && > !is(Unqual!(R) T == Take!(T))) cannot deduce template function from argument > types !()(Recurrence!(fun,long,2u),immutable(long)) > > which seems deeply impenetrable for mere mortals. Sorry I needed to add the driver code: foreach ( item ; data ) { assert ( declarative ( item[0] ) == item[1] ) ; } within a unittest block. -- Russel. = Dr Russel Winder t: +44 20 7585 2200 voip: sip:russel.win...@ekiga.net 41 Buckmaster Roadm: +44 7770 465 077 xmpp: rus...@russel.org.uk London SW11 1EN, UK w: www.russel.org.uk skype: russel_winder signature.asc Description: This is a digitally signed message part
Re: Fibonacci with ranges
On Fri, 2011-03-11 at 18:46 -0500, Jesse Phillips wrote: > Without testing: foreach (f; take(recurrence!("a[n-1] + a[n-2]")(0UL, 1UL), > 50)) > > teo Wrote: > > > Just curious: How can I get ulong here? > > > > foreach (f; take(recurrence!("a[n-1] + a[n-2]")(0, 1), 50)) > > { > > writeln(f); > > } > Interestingly, or not, the code: long declarative ( immutable long n ) { return take ( recurrence ! ( "a[n-1] + a[n-2]" ) ( 0L , 1L ) , n ) ; } results in the return statement delivering: rdmd --main -unittest fibonacci_d2.d fibonacci_d2.d(15): Error: template std.range.take(R) if (isInputRange!(Unqual!(R)) && !isSafelySlicable!(Unqual!(R)) && !is(Unqual!(R) T == Take!(T))) does not match any function template declaration fibonacci_d2.d(15): Error: template std.range.take(R) if (isInputRange!(Unqual!(R)) && !isSafelySlicable!(Unqual!(R)) && !is(Unqual!(R) T == Take!(T))) cannot deduce template function from argument types !()(Recurrence!(fun,long,2u),immutable(long)) which seems deeply impenetrable for mere mortals. -- Russel. = Dr Russel Winder t: +44 20 7585 2200 voip: sip:russel.win...@ekiga.net 41 Buckmaster Roadm: +44 7770 465 077 xmpp: rus...@russel.org.uk London SW11 1EN, UK w: www.russel.org.uk skype: russel_winder signature.asc Description: This is a digitally signed message part