digitalmars.D - Do we really need const?
- Bill Baxter (27/40) Sep 16 2007 That's a very good point. *Are* there any others? Pascal seems to have...
- Don Clugston (8/12) Sep 17 2007 I'm thinking the same way. There are clear benefits to 'pure', with both...
- Bruce Adams (2/16) Sep 17 2007 From what I've seen here. Talking in this group all day long doesn't see...
- Bruce Adams (6/55) Sep 17 2007 Arguing that something isn't useful because you can live without it is
- Matti Niemenmaa (7/9) Sep 17 2007 Java has a limited form of const in final, which allows for both compile...
- Bill Baxter (5/14) Sep 17 2007 Yes, a lot of languages seem to have that form of const, which is more
- Regan Heath (10/25) Sep 17 2007 Java also has invariant strings which is another form of const, one that...
- Regan Heath (4/5) Sep 17 2007 This was badly named, I really mean "invariant references/pointers".
- Matti Niemenmaa (5/14) Sep 17 2007 No. But it's more than D1.x's const, in that it can be used other than j...
- Regan Heath (3/15) Sep 17 2007 It's like D2.0's 'final' then.
- Matti Niemenmaa (4/21) Sep 17 2007 Yep.
- Lionello Lunesu (24/24) Sep 17 2007 Just a quick note to say that I also have never missed "const" in D and
- Jan Claeys (5/6) Sep 17 2007 Python has immutable objects (e.g. strings & tuples). :)
- Bill Baxter (6/12) Sep 17 2007 Yeh I'm really thinking more about the type of const that appears in
- Walter Bright (4/10) Sep 17 2007 A lot of Python users also seem to be quite unhappy about the gil.
- Jan Claeys (20/23) Sep 22 2007 Actually, only some Python implementation have the GIL (CPython &
- Daniel Keep (13/22) Sep 22 2007 To be fair, that's parallelism via stackless which is just cooperative
- Jan Claeys (15/31) Sep 24 2007 Not multiple threads of pure python code, but modules written in C++
- Bill Baxter (19/25) Sep 22 2007 Actually I remembered one time when lack of const did bite me in Python....
- Jan Claeys (17/27) Sep 24 2007 Never do a word-by-word translation... :)
- Jarrett Billingsley (16/21) Sep 17 2007 I start to wonder how much of the "of COURSE we need const!" thinking co...
- Christopher Wright (10/33) Sep 17 2007 I think it would be a comfort to have it for function signatures, but
- Walter Bright (6/10) Sep 17 2007 The reason that C++ member functions are written twice, const and
- Bill Baxter (4/17) Sep 17 2007 There's also the practice of writing all iterators twice. One tail
- Robert Fraser (2/28) Sep 17 2007 You put it a lot better than I did. High-five!
- Bill Baxter (4/10) Sep 18 2007 I was a little over-zealous in my condemnation here. I should have said...
- Janice Caron (54/75) Sep 19 2007 Let me share some real world experience about using const versus not
- Steven Schveighoffer (14/27) Sep 19 2007 Something tells me that this friend of yours would have done the same th...
- Janice Caron (9/12) Sep 19 2007 Difficult to say. Everyone hesitates before typing "const_cast"! Even
- Robert Fraser (2/90) Sep 19 2007
- Bill Baxter (13/87) Sep 19 2007 First, I'm not convinced that cluebie wouldn't have just casted away
- Janice Caron (5/6) Sep 19 2007 Oh dear. I hope I'm not being misunderstood again.
- Bruce Adams (11/36) Sep 17 2007 The problem with this is it isn't easy to tell how many problems would h...
- Robert Fraser (4/7) Sep 17 2007 I think this is a similar argument to the one used to argue that static ...
- Bruce Adams (9/17) Sep 17 2007 The same argument can be applied to unit testing and contracts as well b...
- 0ffh (10/18) Sep 17 2007 As an aside, I think that people tend to use one bin for dynamic typing
- renoX (17/19) Sep 17 2007 If it helps you'not the only one to have this kind of issue: some
- Regan Heath (3/16) Sep 17 2007 My eyes... aaarghh!
- Bill Baxter (8/24) Sep 17 2007 Is it the particular syntax or the concept you object to? I think
- Bruce Adams (30/57) Sep 17 2007 Actually I quite like the concept of keywords provided they're optional.
- Regan Heath (21/46) Sep 18 2007 Not sure, it just makes my skin crawl at the moment. I've never really
- Janice Caron (4/20) Sep 18 2007 Of course, for copying strings in D, we already have the vastly superior...
- Regan Heath (4/23) Sep 18 2007 You mean of course:
- Janice Caron (2/5) Sep 18 2007 Oh yeah! Well spotted. :-)
- Frits van Bommel (11/38) Sep 18 2007 Or:
- renoX (21/74) Sep 18 2007 The IDE can write these thing for you (assuming of course you write the
- Regan Heath (6/12) Sep 19 2007 Which they do using what application ;) The IDE, which can display the
- Ingo Oeser (8/16) Sep 23 2007 Really, not every developer is using some kind of IDE.
- Robert Fraser (2/23) Sep 23 2007 But should language features be added to maker reading code easier?
- Derek Parnell (9/10) Sep 23 2007 YES YES YES! (imnsho)
- Ingo Oeser (20/21) Sep 24 2007 Yes. Many projects use domain specific languages to make the code more
- Derek Parnell (8/24) Sep 17 2007 Or ...
- Derek Parnell (12/34) Sep 17 2007 P.S.
- Jarrett Billingsley (4/5) Sep 17 2007 My eyes... ahhhh! They feel so good having seen such self-explanatory c...
- Robert Fraser (7/11) Sep 17 2007 In other words, all exceptions are checked exceptions...? This would esp...
- Jarrett Billingsley (18/20) Sep 17 2007 Bit of a sidetrack here. Dynamic typing, in the sense that variables do...
- Jari-Matti =?ISO-8859-1?Q?M=E4kel=E4?= (8/17) Sep 17 2007 Of course type systems aren't one dimensional - there can be several kin...
- Bill Baxter (78/95) Sep 17 2007 Note however that as these languages mature people are gradually trying
- Bruce Adams (2/17) Sep 18 2007 So in other words the duck stops here ;)
- Bruce Adams (5/119) Sep 18 2007 Showing my true colours as a D noob here. I thought that with D like in ...
- Walter Bright (9/22) Sep 17 2007 At the upcoming http://www.astoriaseminar.com, I think I'll do some
- Robert Fraser (4/33) Sep 17 2007 Same with const, but top-down. Make something const in A, you have to ma...
- Walter Bright (8/16) Sep 18 2007 The problem with docs is they are invariably wrong, out of date,
- Janice Caron (144/153) Sep 18 2007 The issues in C++ aren't necessarily the same as the issues in D,
- Janice Caron (41/41) Sep 18 2007 About passing structs by reference: It's one of those things, like
- Bill Baxter (34/53) Sep 18 2007 This thought has occurred to me before to. I think issue becomes that
- Janice Caron (5/8) Sep 18 2007 That is also true for inline.
- Bill Baxter (3/13) Sep 18 2007 So the compiler generates 2^N versions for an N-parameter method?
- Janice Caron (13/14) Sep 18 2007 Still only two ... I /think/
- Bill Baxter (6/17) Sep 18 2007 That makes sense and seems like it could work if you have const refs to
- Ingo Oeser (8/21) Sep 18 2007 No, just for the cases, where it really matters in code size and/or spee...
- Janice Caron (15/41) Sep 18 2007 Actually, I think it's possible my proposal may not have been
- Bill Baxter (8/58) Sep 18 2007 Yeh, sorry my response was more along the lines of "that's an
- Bruce Adams (3/42) Sep 18 2007 S could be an opaque type so s.sizeof may still be undefined.
- Bill Baxter (8/47) Sep 18 2007 You can't declare a function that takes an argument of unknown size.
- Bruce Adams (7/57) Sep 18 2007 See my reply to Janice on channel B.
- Reiner Pope (10/70) Sep 18 2007 These opaque types sound suspiciously like D classes/interfaces.
- Janice Caron (9/22) Sep 18 2007 Could you explain further? I don't understand what an "opaque type" is
- Bruce Adams (11/35) Sep 18 2007 Right. That was additional information I lost somewhere.
- Nathan Reed (7/8) Sep 18 2007 It's true. Why do you find this peculiar? Structs are aggregate data
- Bruce Adams (4/16) Sep 18 2007 That's not the same at all. There are internationally approved standards...
- Bill Baxter (7/26) Sep 18 2007 Any Walter-approved ABI standards for the D compiler are basically
- Jascha Wetzel (5/28) Sep 18 2007 we still need a solution to force pass-by-value and pass-by-reference
- Janice Caron (3/5) Sep 18 2007 What I mean was defined in a previous post - hopefully fairly
- renoX (10/20) Sep 18 2007 Well in some (very limited) cases, they still do: I'm thinking about the...
- Bruce Adams (4/20) Sep 18 2007 Its not just in the Kernel. It comes up relatively frequently when deali...
Bruce Adams wrote:charles Wrote:ever >> had a situation where const actually paid off.Const is a god awful abomination that no language has gotten right, the sooner its gotten rid of the better. No one I work with hasAs a seasoned C++ programmer I and my colleagues regularly use the c++ flavour of const with no problems. It may not be the best solution in the world but it works. I always found it a reasonably intuitive bit of syntactic sugar. That's not to say that we can't do better in D. I'd recommend reading Scott Meyers effective C++ books for a start. And perhaps we should review the deliberations that went into developing the C++ const system.By the way, what languages other than C++ have some kind of const mechanism? They've got to be worth a review too.That's a very good point. *Are* there any others? Pascal seems to have some form of it (http://www.gnu-pascal.de/gpc/const.html). Any Pascal devotees out there care to comment? I managed to avoid ever learning Pascal. Anyway, if one asserts that const is a critical feature for "enterprise code", yet there exist a large body of "enterprise code" written in languages that don't have const, then we have a contradiction. It can't be all that critical if lots of successful software projects get written without it. There's of course Java. Lots of enterprise software is written in Java, and yet Java does not have const. There is without a doubt some diagnostic benefit to const, but if it were such a great win overall wouldn't everybody be doing it? Is it really worth the pain of having to create two versions of every function, and two flavors of every iterator, etc.? I guess I've gotten used to it in C++ and certainly bought into the const-correctness mantra. When I see C++ code that doesn't use const correctly my kneejerk reaction is always "sheesh -- amateur". But I've never really taken a step back to try to seriously evaluate the cost-benefit tradeoff. It seems from the discussion here the past week, there is no real multithreading benefit to be had from const/invariant. 'Pure' is where it's at for that. So maybe we're just better off without the complexities of const. I've certainly gotten used to the lack of const in Python, so why not in a C++-ish language? --bb
Sep 16 2007
Bill Baxter wrote:It seems from the discussion here the past week, there is no real multithreading benefit to be had from const/invariant. 'Pure' is where it's at for that. So maybe we're just better off without the complexities of const.I'm thinking the same way. There are clear benefits to 'pure', with both multi-threading and optimisation, and it's conceptually simple and easy to explain to a newbie. But 'const' seems to be a horrible morass, complicated to explain, complicated to code, and with very little benefit. At the very least, it's clear that 'const' has cost the D community a huge amount of discussion bandwidth and mental space, with very little of use to show for it. We may be caught in a productivity trap.
Sep 17 2007
Don Clugston Wrote:Bill Baxter wrote:From what I've seen here. Talking in this group all day long doesn't seem to affect productivity that badly. ;)It seems from the discussion here the past week, there is no real multithreading benefit to be had from const/invariant. 'Pure' is where it's at for that. So maybe we're just better off without the complexities of const.I'm thinking the same way. There are clear benefits to 'pure', with both multi-threading and optimisation, and it's conceptually simple and easy to explain to a newbie. But 'const' seems to be a horrible morass, complicated to explain, complicated to code, and with very little benefit. At the very least, it's clear that 'const' has cost the D community a huge amount of discussion bandwidth and mental space, with very little of use to show for it. We may be caught in a productivity trap.
Sep 17 2007
Bill Baxter Wrote:Bruce Adams wrote: > charles Wrote: > >> Const is a god awful abomination that no language has gotten right, >> the sooner its gotten rid of the better. No one I work with has ever >> had a situation where const actually paid off. >>Arguing that something isn't useful because you can live without it is not sound. I can live without a dish-washer but I'd rather not have to do the washing up myself. Similarly the GIT people seem perfectly happy to write all their code in C, and from my brief glance at their code base its quite neat. Its a case of working smarter versus working harder. That said, its better to wait and deliberate and get a good const system rather than live with something that's not up to par. I can't really comment on pascal myself. I did do some modula-2 many years ago, which I consider to be 2 steps on from pascal in Wirths evolution (pascal, modula 1,2,3 then oberon). I think const is just used for variables assigned once and ideally at compile time when the expression permits it. Regards, Bruce.As a seasoned C++ programmer I and my colleagues regularly use the c++ flavour of const with no problems. It may not be the best solution in the world but it works. I always found it a reasonably intuitive bit of syntactic sugar. That's not to say that we can't do better in D. I'd recommend reading Scott Meyers effective C++ books for a start. And perhaps we should review the deliberations that went into developing the C++ const system.By the way, what languages other than C++ have some kind of const> mechanism? They've got to be worth a review too. That's a very good point. *Are* there any others? Pascal seems to have some form of it (http://www.gnu-pascal.de/gpc/const.html). Any Pascal devotees out there care to comment? I managed to avoid ever learning Pascal. Anyway, if one asserts that const is a critical feature for "enterprise code", yet there exist a large body of "enterprise code" written in languages that don't have const, then we have a contradiction. It can't be all that critical if lots of successful software projects get written without it. There's of course Java. Lots of enterprise software is written in Java, and yet Java does not have const. There is without a doubt some diagnostic benefit to const, but if it were such a great win overall wouldn't everybody be doing it? Is it really worth the pain of having to create two versions of every function, and two flavors of every iterator, etc.? I guess I've gotten used to it in C++ and certainly bought into the const-correctness mantra. When I see C++ code that doesn't use const correctly my kneejerk reaction is always "sheesh -- amateur". But I've never really taken a step back to try to seriously evaluate the cost-benefit tradeoff. It seems from the discussion here the past week, there is no real multithreading benefit to be had from const/invariant. 'Pure' is where it's at for that. So maybe we're just better off without the complexities of const. I've certainly gotten used to the lack of const in Python, so why not in a C++-ish language? --bb
Sep 17 2007
Bill Baxter wrote:There's of course Java. Lots of enterprise software is written in Java, and yet Java does not have const.Java has a limited form of const in final, which allows for both compile-time constants and variables which can only be assigned to once. See the "variables" and "fields" sections here: http://renaud.waldura.com/doc/java/final-keyword.shtml -- E-mail address: matti.niemenmaa+news, domain is iki (DOT) fi
Sep 17 2007
Matti Niemenmaa wrote:Bill Baxter wrote:Yes, a lot of languages seem to have that form of const, which is more or less like const is in D1.x. That doesn't seem to be the problematic kind. --bbThere's of course Java. Lots of enterprise software is written in Java, and yet Java does not have const.Java has a limited form of const in final, which allows for both compile-time constants and variables which can only be assigned to once. See the "variables" and "fields" sections here: http://renaud.waldura.com/doc/java/final-keyword.shtml
Sep 17 2007
Bill Baxter wrote:Matti Niemenmaa wrote:Java also has invariant strings which is another form of const, one that makes multithreading easier. It seems that there are at least 4 forms of const: 1. invariant data 2. invariant variables 3. logical const 4. transitive const ReganBill Baxter wrote:Yes, a lot of languages seem to have that form of const, which is more or less like const is in D1.x. That doesn't seem to be the problematic kind.There's of course Java. Lots of enterprise software is written in Java, and yet Java does not have const.Java has a limited form of const in final, which allows for both compile-time constants and variables which can only be assigned to once. See the "variables" and "fields" sections here: http://renaud.waldura.com/doc/java/final-keyword.shtml
Sep 17 2007
Regan Heath wrote:2. invariant variablesThis was badly named, I really mean "invariant references/pointers". Regan
Sep 17 2007
Bill Baxter wrote:Matti Niemenmaa wrote:No. But it's more than D1.x's const, in that it can be used other than just for compile time constants. -- E-mail address: matti.niemenmaa+news, domain is iki (DOT) fiJava has a limited form of const in final, which allows for both compile-time constants and variables which can only be assigned to once. See the "variables" and "fields" sections here: http://renaud.waldura.com/doc/java/final-keyword.shtmlYes, a lot of languages seem to have that form of const, which is more or less like const is in D1.x. That doesn't seem to be the problematic kind.
Sep 17 2007
Matti Niemenmaa wrote:Bill Baxter wrote:It's like D2.0's 'final' then. ReganMatti Niemenmaa wrote:No. But it's more than D1.x's const, in that it can be used other than just for compile time constants.Java has a limited form of const in final, which allows for both compile-time constants and variables which can only be assigned to once. See the "variables" and "fields" sections here: http://renaud.waldura.com/doc/java/final-keyword.shtmlYes, a lot of languages seem to have that form of const, which is more or less like const is in D1.x. That doesn't seem to be the problematic kind.
Sep 17 2007
Regan Heath wrote:Matti Niemenmaa wrote:Yep. -- E-mail address: matti.niemenmaa+news, domain is iki (DOT) fiBill Baxter wrote:It's like D2.0's 'final' then.Matti Niemenmaa wrote:No. But it's more than D1.x's const, in that it can be used other than just for compile time constants.Java has a limited form of const in final, which allows for both compile-time constants and variables which can only be assigned to once. See the "variables" and "fields" sections here: http://renaud.waldura.com/doc/java/final-keyword.shtmlYes, a lot of languages seem to have that form of const, which is more or less like const is in D1.x. That doesn't seem to be the problematic kind.
Sep 17 2007
Just a quick note to say that I also have never missed "const" in D and am reluctant to start with D 2.0 because of the added complexity. Walter has said himself that while porting Phobos to 2.0, he has not encountered, let alone fixed, a single bug. For me, const/final/invariant is just not worth it. I like const conceptually, but then there are many similar concepts that are nice and const is just one of them. D should opt for a more general red code / green code mechanism, as explained by Scott Meyers in the next video: http://video.google.com/videoplay?docid=-4728145737208991310 Pure/not-pure, throw/no-throw, const/not-const, threadsafe/not-threadsafe etc. are all similar and I would love to see one solution for all these red/green restrictions. L. PS. I'm playing around with the idea to add keywords after a function declaration to add labels to the function. The compiler should then only accept calls to functions with at least the labels of the caller: void bar() throw; void foo() { bar(); }//ERROR, bar can throw void foo2() throw { bar(); } //OK void foo3() throw { bar() throw; } //OK ("cast") Or something to that effect. Possible using "!" to negate (!throw). I have not thought this through more than what's written here and have no idea what it would imply for the grammar.
Sep 17 2007
Op Mon, 17 Sep 2007 15:36:35 +0900 schreef Bill Baxter <dnewsgroup billbaxter.com>:I've certainly gotten used to the lack of const in PythonPython has immutable objects (e.g. strings & tuples). :) -- JanC
Sep 17 2007
Jan Claeys wrote:Op Mon, 17 Sep 2007 15:36:35 +0900 schreef Bill Baxter <dnewsgroup billbaxter.com>:Yeh I'm really thinking more about the type of const that appears in front of parameters to functions, and forces you to write all your from Regan's list. :-) --bbI've certainly gotten used to the lack of const in PythonPython has immutable objects (e.g. strings & tuples). :)
Sep 17 2007
Jan Claeys wrote:Op Mon, 17 Sep 2007 15:36:35 +0900 schreef Bill Baxter <dnewsgroup billbaxter.com>:A lot of Python users also seem to be quite unhappy about the gil. Python in its current form appears to be unsuitable for writing parallel code.I've certainly gotten used to the lack of const in PythonPython has immutable objects (e.g. strings & tuples). :)
Sep 17 2007
Op Mon, 17 Sep 2007 23:00:33 -0700 schreef Walter Bright <newshound1 digitalmars.com>:A lot of Python users also seem to be quite unhappy about the gil.Actually, only some Python implementation have the GIL (CPython & Stackless), most don't have it (Jython, IronPython, PyPy, etc.). Of course CPython is probably used more than all others combined...Python in its current form appears to be unsuitable for writing parallel code.There are lots of (sometimes massively) parallel python applications around; some of them were named in the recent discussions. As an example, the EVE Online servers & clients work as one large distributed parallel application (there is one shared "state"). The complaints seem to be more about how people have to write parallel code, but trying to port Java/C++ code/idioms word for word into Python (obviously) doesn't work very well. AFAIK most CPython parallel programming uses one of two techniques: 1. Non-Python modules (e.g. those written in C, C++ or D) can (temporarily) release the GIL if they make sure they don't access/change data shared with other threads during that period. 2. Multiple processes + some form of IPC (machine-local or distributed over a cluster) -- JanC
Sep 22 2007
Jan Claeys wrote:Op Mon, 17 Sep 2007 23:00:33 -0700 schreef Walter Bright <newshound1 digitalmars.com>:To be fair, that's parallelism via stackless which is just cooperative multithreading. As far as I understand it, if you ignore the overhead of context switching and locks, code written against stackless and using Python threads will run at the same speed irrespective of how many hardware threads you have. Neither one, AFAIK, can actually execute multiple threads of Python code simultaneously. That said, stackless is still the bee's knees if you're on a uniprocessor machine. The ability to have hundreds of thousands of super lightweight threads with almost no overhead, *and* the ability to just pickle a thread and re-start it on another machine? And people wonder why the EVE guys get so excited by it :P -- DanielPython in its current form appears to be unsuitable for writing parallel code.There are lots of (sometimes massively) parallel python applications around; some of them were named in the recent discussions. As an example, the EVE Online servers & clients work as one large distributed parallel application (there is one shared "state").
Sep 22 2007
Op Sun, 23 Sep 2007 16:16:03 +1000 schreef Daniel Keep <daniel.keep.lists gmail.com>:Jan Claeys wrote:Not multiple threads of pure python code, but modules written in C++ (which I think they use at least in the client, and most likely also server-side) can use multiple simultaneous threads. And multiple processes + IPC are no problem for pure python code.There are lots of (sometimes massively) parallel python applications around; some of them were named in the recent discussions. As an example, the EVE Online servers & clients work as one large distributed parallel application (there is one shared "state").To be fair, that's parallelism via stackless which is just cooperative multithreading. As far as I understand it, if you ignore the overhead of context switching and locks, code written against stackless and using Python threads will run at the same speed irrespective of how many hardware threads you have. Neither one, AFAIK, can actually execute multiple threads of Python code simultaneously.That said, stackless is still the bee's knees if you're on a uniprocessor machine. The ability to have hundreds of thousands of super lightweight threads with almost no overhead, *and* the ability to just pickle a thread and re-start it on another machine?They run it on a cluster of several multiprocessor machines, not even counting the tens of thousands of PCs of their customers (the players of the game) that have to share (part of) the state of the game. <http://myeve.eve-online.com/devblog.asp?a=blog&bid=303> tells about their early 2006 hardware (70 dual-cpu IBM LS20 Opteron blades :) ). On 2007-09-03 they had more than 35000 people logged in into the same game: <http://www.gamershell.com/news/41371.html>. -- JanC
Sep 24 2007
Jan Claeys wrote:Op Mon, 17 Sep 2007 15:36:35 +0900 schreef Bill Baxter <dnewsgroup billbaxter.com>:Actually I remembered one time when lack of const did bite me in Python. I was translating some Matlab code I wrote to Python/NumPy (http://www.scipy.org/). In Matlab all calls are call-by-value, and all assignments are assign-by-value (both use COW under the covers to make performance reasonable). In Python they're call-by-reference and assign-by-reference for most anything more complicated than an 'int'. The matrix class I was using in the Python code definitely fell into the by-reference category. After I got the port basically working there were quite a few bugs that turned out to be a result of functions I translated from Matlab modifying their arguments. If Python had const, I don't think I would have had those problems. On the other hand, the NumPy matrix class itself has a read-only flag. If I were porting to Python again I'd probably try to write a decorator to use during debugging that sets that readonly flag before entering the function and unsets it on return. --bbI've certainly gotten used to the lack of const in PythonPython has immutable objects (e.g. strings & tuples). :)
Sep 22 2007
Op Sun, 23 Sep 2007 15:48:08 +0900 schreef Bill Baxter <dnewsgroup billbaxter.com>:Actually I remembered one time when lack of const did bite me in Python. I was translating some Matlab code I wrote to Python/NumPy (http://www.scipy.org/). In Matlab all calls are call-by-value, and all assignments are assign-by-value (both use COW under the covers to make performance reasonable). In Python they're call-by-reference and assign-by-reference for most anything more complicated than an 'int'. The matrix class I was using in the Python code definitely fell into the by-reference category.Never do a word-by-word translation... :) Both mutable & immutable objects are passed as "objects" in python (the technical details of how that happens, e.g. using pointers, is merely an implementation detail, but it's obviously very close to what happens with call-by-reference in other languages) and it's only at the time of assignment that behaviour between them differs. It's the same outside of a function/method and has nothing to do with the different methods of parameter passing in other languages.If Python had const, I don't think I would have had those problems.Well, Python has something 'const'-like, only it's linked to the object's type, and not defined by the way it's called. ;) And if you want to "call by value", there is always the 'copy' module: <http://docs.python.org/lib/module-copy.html> (Could be used in a decorator too...) -- JanC
Sep 24 2007
"Bill Baxter" <dnewsgroup billbaxter.com> wrote in message news:fcl79k$18vu$1 digitalmars.com...It seems from the discussion here the past week, there is no real multithreading benefit to be had from const/invariant. 'Pure' is where it's at for that. So maybe we're just better off without the complexities of const. I've certainly gotten used to the lack of const in Python, so why not in a C++-ish language?I start to wonder how much of the "of COURSE we need const!" thinking comes from "if all you have is a hammer, everything starts looking like a nail." That is, I wonder how many people think we absolutely need const because they're so used to using it in C and C++. Never having learned a const-correct language (started with various BASICs, simply don't see the overwhelming need. Sure, there are a very few cases where const could be useful in my code for efficiency's sake, but I've never felt like I was missing any expressive power. Furthermore, I have been bitten exactly once by something that theoretically could have been prevented by const. It took me two minutes in the debugger to track down the problem. I'd say that those two minutes were a much better tradeoff than the god-knows-how-long it'd take to write const and non-const overloads of who-knows-how-many functions.
Sep 17 2007
Jarrett Billingsley wrote:"Bill Baxter" <dnewsgroup billbaxter.com> wrote in message news:fcl79k$18vu$1 digitalmars.com...I think it would be a comfort to have it for function signatures, but I've only been affected by it once -- with getopt on C. (And getopt is an ugly, horrible thing. _Why_ does it modify the command line arguments?) Other than that, D2 invariant and final seem useful. D2 const is good for basic things, but seems to scale poorly.It seems from the discussion here the past week, there is no real multithreading benefit to be had from const/invariant. 'Pure' is where it's at for that. So maybe we're just better off without the complexities of const. I've certainly gotten used to the lack of const in Python, so why not in a C++-ish language?I start to wonder how much of the "of COURSE we need const!" thinking comes from "if all you have is a hammer, everything starts looking like a nail." That is, I wonder how many people think we absolutely need const because they're so used to using it in C and C++.Never having learned a const-correct language (started with various BASICs, simply don't see the overwhelming need. Sure, there are a very few cases where const could be useful in my code for efficiency's sake, but I've never felt like I was missing any expressive power. Furthermore, I have been bitten exactly once by something that theoretically could have been prevented by const. It took me two minutes in the debugger to track down the problem. I'd say that those two minutes were a much better tradeoff than the god-knows-how-long it'd take to write const and non-const overloads of who-knows-how-many functions.Most of the time, you shouldn't need to write those overloads. Either the function can be const, in which case you can use it with mutable data anyway, or it can't, in which case you can't write a const overload for it. At least in an ideal system.
Sep 17 2007
Christopher Wright wrote:Most of the time, you shouldn't need to write those overloads. Either the function can be const, in which case you can use it with mutable data anyway, or it can't, in which case you can't write a const overload for it. At least in an ideal system.The reason that C++ member functions are written twice, const and non-const, are to transmit the const to the return type: const T foo(const S); T foo(S); Nothing more.
Sep 17 2007
Walter Bright wrote:Christopher Wright wrote:There's also the practice of writing all iterators twice. One tail const, one tail mutable. --bbMost of the time, you shouldn't need to write those overloads. Either the function can be const, in which case you can use it with mutable data anyway, or it can't, in which case you can't write a const overload for it. At least in an ideal system.The reason that C++ member functions are written twice, const and non-const, are to transmit the const to the return type: const T foo(const S); T foo(S); Nothing more.
Sep 17 2007
Jarrett Billingsley Wrote:"Bill Baxter" <dnewsgroup billbaxter.com> wrote in message news:fcl79k$18vu$1 digitalmars.com...You put it a lot better than I did. High-five!It seems from the discussion here the past week, there is no real multithreading benefit to be had from const/invariant. 'Pure' is where it's at for that. So maybe we're just better off without the complexities of const. I've certainly gotten used to the lack of const in Python, so why not in a C++-ish language?I start to wonder how much of the "of COURSE we need const!" thinking comes from "if all you have is a hammer, everything starts looking like a nail." That is, I wonder how many people think we absolutely need const because they're so used to using it in C and C++. Never having learned a const-correct language (started with various BASICs, simply don't see the overwhelming need. Sure, there are a very few cases where const could be useful in my code for efficiency's sake, but I've never felt like I was missing any expressive power. Furthermore, I have been bitten exactly once by something that theoretically could have been prevented by const. It took me two minutes in the debugger to track down the problem. I'd say that those two minutes were a much better tradeoff than the god-knows-how-long it'd take to write const and non-const overloads of who-knows-how-many functions.
Sep 17 2007
Jarrett Billingsley wrote:"Bill Baxter" <dnewsgroup billbaxter.com> wrote in message news:fcl79k$18vu$1 digitalmars.com...I was a little over-zealous in my condemnation here. I should have said just "const" not "const/invariant". --bbIt seems from the discussion here the past week, there is no real multithreading benefit to be had from const/invariant. 'Pure' is where it's at for that.
Sep 18 2007
On 9/17/07, Jarrett Billingsley <kb3ctd2 yahoo.com> wrote:"Bill Baxter" <dnewsgroup billbaxter.com> wrote in message news:fcl79k$18vu$1 digitalmars.com...Let me share some real world experience about using const versus not using const. Today, I found myself writing a small standalone project in D, for my own personal use. I wrote a function that took a ubtye[] as it's parameter. It occured to me that the function didn't actually modify the array, so (since I have D2.0) I could have declared the parameter const. I considered it, and then I thought: "Nah... let's not bother. Too much effort". BUT... When working on a big project, it's a different story. A couple of years back, I was team leader in a C++ project with half a dozen other developers. It was a multithreaded application. So I wrote this bunch of classes which had to be called in a certain way or it wouldn't compile - because data had to be shared between server instances and so forth. Well, a couple of the developers figured out the right thing to do all by themselves, and that was great. Of the others, about three tried the "obvious", discovered that it wouldn't compile because of const-correctness, and came to me asking why not. I explained that there was good reason for the constness, that it was thread-safety issue, and then I told them the correct, "authorised" way of doing things, and then they went off and did the right thing. So in this case, const forced everyone to get it right. Well - almost everyone. (There's always /one/!) One team member tried the "obvious", discovered that it wouldn't compile, and then, instead of asking me why not, figured out a workaround to make it compile using pointers. (If C++ had had intransitive const, the compiler would have prevented this, but it doesn't so he got away with it). Then ... weeks later ... we found that the server randomly fell over after several hours of problem-free up-time. The symptoms were random memory corruption. It took us about a month to find and fix the problem! Care to guess what the problem turned out to be? Yes, it was that errant team member's workaround for const-correctness that ended up causing multiple threads to (rarely) become thread-unsafe. (Moral: If your code won't compile when you try to call a co-worker's function, don't hack up a workaround - instead, ask them if you're calling it right!) So what I conclude from this is: (1) For a small project, you can ignore const. Just because the language has it, doesn't mean you have to use it. (2) For a large project, it's essential. And moreover, it needs to be transitive by default. I don't have a problem with const being transitive by default. I think it's a good idea. I do, however, have a problem with there being *no way to specify* mutable pointer to const pointer to mutable data. We've listed enough use cases to know that sometimes that's exactly what you need. It shouldn't be the default, but it should be /possible/. But ... on the other hand ... we /can/ cast away const, and even though it's "undefined", there is some indication that you can get away with it if you know what you're doing (in terms of thread-safety), so maybe it's not as big a problem as some of us imagine. Anyway, there's my story and my conclusions. Hope it helps. If not, hope it kept you amused. :-)It seems from the discussion here the past week, there is no real multithreading benefit to be had from const/invariant. 'Pure' is where it's at for that. So maybe we're just better off without the complexities of const. I've certainly gotten used to the lack of const in Python, so why not in a C++-ish language?I start to wonder how much of the "of COURSE we need const!" thinking comes from "if all you have is a hammer, everything starts looking like a nail." That is, I wonder how many people think we absolutely need const because they're so used to using it in C and C++. Never having learned a const-correct language (started with various BASICs, simply don't see the overwhelming need. Sure, there are a very few cases where const could be useful in my code for efficiency's sake, but I've never felt like I was missing any expressive power. Furthermore, I have been bitten exactly once by something that theoretically could have been prevented by const. It took me two minutes in the debugger to track down the problem. I'd say that those two minutes were a much better tradeoff than the god-knows-how-long it'd take to write const and non-const overloads of who-knows-how-many functions.
Sep 19 2007
"Janice Caron" wrote(If C++ had had intransitive const, the compiler would have prevented this, but it doesn't so he got away with it).Something tells me that this friend of yours would have done the same thing in D. Is there a warning if you cast away const? If not, there should be. Otherwise, D wouldn't have helped you in this case either...I don't have a problem with const being transitive by default. I think it's a good idea. I do, however, have a problem with there being *no way to specify* mutable pointer to const pointer to mutable data. We've listed enough use cases to know that sometimes that's exactly what you need. It shouldn't be the default, but it should be /possible/. But ... on the other hand ... we /can/ cast away const, and even though it's "undefined", there is some indication that you can get away with it if you know what you're doing (in terms of thread-safety), so maybe it's not as big a problem as some of us imagine.Then why be SO adamant about const being transitive! (i.e. Walter's view, not yours). If the 'accepted' practice is to cast away const if you want to have intransitive const, then transitive const is equally meaningless. The more I think about this issue, the more I think that I can probably live with transitive only const. I don't think it's such a bad thing as it simply makes you think differently when designing classes. As I believe intransitive const is a subset of transitive const, it's almost implementable with transitive-only, but I think I'll probably stay away from it. -Steve
Sep 19 2007
On 9/19/07, Steven Schveighoffer <schveiguy yahoo.com> wrote:Something tells me that this friend of yours would have done the same thing in D. Is there a warning if you cast away const? If not, there should be. Otherwise, D wouldn't have helped you in this case either...Difficult to say. Everyone hesitates before typing "const_cast"! Even when it's legitimate, it feels a bit naughty. Trouble is, the "const_cast" keyword is not compulsory. With C++ is that it isn't immediately obvious that a cast like "(void *)p" is casting away const, but that's what everyone types, because it's quicker than than the safe alternative "static_cast<void *>(p)". That's why I'm hoping Walter will arrange it so that D's "cast(T)" will refuse to cast away constness without a special syntax.
Sep 19 2007
Janice Caron Wrote:On 9/17/07, Jarrett Billingsley <kb3ctd2 yahoo.com> wrote:But wait... if there wasn't any const in the first place, the guy wouldn't have needed to hack up that workaround... I'm sensing a different moral here... ;-P"Bill Baxter" <dnewsgroup billbaxter.com> wrote in message news:fcl79k$18vu$1 digitalmars.com...Let me share some real world experience about using const versus not using const. Today, I found myself writing a small standalone project in D, for my own personal use. I wrote a function that took a ubtye[] as it's parameter. It occured to me that the function didn't actually modify the array, so (since I have D2.0) I could have declared the parameter const. I considered it, and then I thought: "Nah... let's not bother. Too much effort". BUT... When working on a big project, it's a different story. A couple of years back, I was team leader in a C++ project with half a dozen other developers. It was a multithreaded application. So I wrote this bunch of classes which had to be called in a certain way or it wouldn't compile - because data had to be shared between server instances and so forth. Well, a couple of the developers figured out the right thing to do all by themselves, and that was great. Of the others, about three tried the "obvious", discovered that it wouldn't compile because of const-correctness, and came to me asking why not. I explained that there was good reason for the constness, that it was thread-safety issue, and then I told them the correct, "authorised" way of doing things, and then they went off and did the right thing. So in this case, const forced everyone to get it right. Well - almost everyone. (There's always /one/!) One team member tried the "obvious", discovered that it wouldn't compile, and then, instead of asking me why not, figured out a workaround to make it compile using pointers. (If C++ had had intransitive const, the compiler would have prevented this, but it doesn't so he got away with it). Then ... weeks later ... we found that the server randomly fell over after several hours of problem-free up-time. The symptoms were random memory corruption. It took us about a month to find and fix the problem! Care to guess what the problem turned out to be? Yes, it was that errant team member's workaround for const-correctness that ended up causing multiple threads to (rarely) become thread-unsafe. (Moral: If your code won't compile when you try to call a co-worker's function, don't hack up a workaround - instead, ask them if you're calling it right!) So what I conclude from this is: (1) For a small project, you can ignore const. Just because the language has it, doesn't mean you have to use it. (2) For a large project, it's essential. And moreover, it needs to be transitive by default.It seems from the discussion here the past week, there is no real multithreading benefit to be had from const/invariant. 'Pure' is where it's at for that. So maybe we're just better off without the complexities of const. I've certainly gotten used to the lack of const in Python, so why not in a C++-ish language?I start to wonder how much of the "of COURSE we need const!" thinking comes from "if all you have is a hammer, everything starts looking like a nail." That is, I wonder how many people think we absolutely need const because they're so used to using it in C and C++. Never having learned a const-correct language (started with various BASICs, simply don't see the overwhelming need. Sure, there are a very few cases where const could be useful in my code for efficiency's sake, but I've never felt like I was missing any expressive power. Furthermore, I have been bitten exactly once by something that theoretically could have been prevented by const. It took me two minutes in the debugger to track down the problem. I'd say that those two minutes were a much better tradeoff than the god-knows-how-long it'd take to write const and non-const overloads of who-knows-how-many functions.I don't have a problem with const being transitive by default. I think it's a good idea. I do, however, have a problem with there being *no way to specify* mutable pointer to const pointer to mutable data. We've listed enough use cases to know that sometimes that's exactly what you need. It shouldn't be the default, but it should be /possible/. But ... on the other hand ... we /can/ cast away const, and even though it's "undefined", there is some indication that you can get away with it if you know what you're doing (in terms of thread-safety), so maybe it's not as big a problem as some of us imagine. Anyway, there's my story and my conclusions. Hope it helps. If not, hope it kept you amused. :-)
Sep 19 2007
Robert Fraser wrote:Janice Caron Wrote:First, I'm not convinced that cluebie wouldn't have just casted away const to work around D's transitivity. Second, along the same lines as Robert's reply, if you created a library for which in your words "the obvious way" was not the right way to use it, and three developers had to ask you how it works, then it sounds like you may not have documented your cleverness sufficiently. Maybe if you hadn't been thinking compiler errors from constness would save you, then you would have either designed it so that it just worked "the obvious way" or at least documented it more thoroughly. Or was it documented clearly and people just ignored the documentation? That can certainly happen, too. --bbOn 9/17/07, Jarrett Billingsley <kb3ctd2 yahoo.com> wrote:But wait... if there wasn't any const in the first place, the guy wouldn't have needed to hack up that workaround... I'm sensing a different moral here... ;-P"Bill Baxter" <dnewsgroup billbaxter.com> wrote in message news:fcl79k$18vu$1 digitalmars.com...Let me share some real world experience about using const versus not using const. Today, I found myself writing a small standalone project in D, for my own personal use. I wrote a function that took a ubtye[] as it's parameter. It occured to me that the function didn't actually modify the array, so (since I have D2.0) I could have declared the parameter const. I considered it, and then I thought: "Nah... let's not bother. Too much effort". BUT... When working on a big project, it's a different story. A couple of years back, I was team leader in a C++ project with half a dozen other developers. It was a multithreaded application. So I wrote this bunch of classes which had to be called in a certain way or it wouldn't compile - because data had to be shared between server instances and so forth. Well, a couple of the developers figured out the right thing to do all by themselves, and that was great. Of the others, about three tried the "obvious", discovered that it wouldn't compile because of const-correctness, and came to me asking why not. I explained that there was good reason for the constness, that it was thread-safety issue, and then I told them the correct, "authorised" way of doing things, and then they went off and did the right thing. So in this case, const forced everyone to get it right. Well - almost everyone. (There's always /one/!) One team member tried the "obvious", discovered that it wouldn't compile, and then, instead of asking me why not, figured out a workaround to make it compile using pointers. (If C++ had had intransitive const, the compiler would have prevented this, but it doesn't so he got away with it). Then ... weeks later ... we found that the server randomly fell over after several hours of problem-free up-time. The symptoms were random memory corruption. It took us about a month to find and fix the problem! Care to guess what the problem turned out to be? Yes, it was that errant team member's workaround for const-correctness that ended up causing multiple threads to (rarely) become thread-unsafe. (Moral: If your code won't compile when you try to call a co-worker's function, don't hack up a workaround - instead, ask them if you're calling it right!) So what I conclude from this is: (1) For a small project, you can ignore const. Just because the language has it, doesn't mean you have to use it. (2) For a large project, it's essential. And moreover, it needs to be transitive by default.It seems from the discussion here the past week, there is no real multithreading benefit to be had from const/invariant. 'Pure' is where it's at for that. So maybe we're just better off without the complexities of const. I've certainly gotten used to the lack of const in Python, so why not in a C++-ish language?I start to wonder how much of the "of COURSE we need const!" thinking comes from "if all you have is a hammer, everything starts looking like a nail." That is, I wonder how many people think we absolutely need const because they're so used to using it in C and C++. Never having learned a const-correct language (started with various BASICs, simply don't see the overwhelming need. Sure, there are a very few cases where const could be useful in my code for efficiency's sake, but I've never felt like I was missing any expressive power. Furthermore, I have been bitten exactly once by something that theoretically could have been prevented by const. It took me two minutes in the debugger to track down the problem. I'd say that those two minutes were a much better tradeoff than the god-knows-how-long it'd take to write const and non-const overloads of who-knows-how-many functions.
Sep 19 2007
On 9/19/07, Robert Fraser <fraserofthenight gmail.com> wrote:But wait... if there wasn't any const in the first place, the guy wouldn't have needed to hack up that workaround...Oh dear. I hope I'm not being misunderstood again. const forced the rest of the team (apart from this one guy) to get it right. That meant the project ended up relatively bug free. This one guy was the exception that proves the rule!
Sep 19 2007
Jarrett Billingsley Wrote:"Bill Baxter" <dnewsgroup billbaxter.com> wrote in message news:fcl79k$18vu$1 digitalmars.com...The problem with this is it isn't easy to tell how many problems would have been prevented if you are a regular user of const because they've been prevented. One exercise to try would be to take a large project and replace const with an empty string and see what the code looks like, then count the number, type and severity of potential errors relating to this absence. The problem is that doesn't take into account the dynamic nature of programming. Far more mistakes occur during development than you might be able to find in a finished product. An example of one that catches me out quite often is: strcpy(src,dest) vs. strcpy(dest,src); As soon as src is const and dest mustn't be this can be caught at compile time. Granted that example is academic as I use std::string in place of char*s whenever possible. So that's one use case in favour of const parameters. What happened to that "deconstructing the christmas tree" thread? Gathering the useful use cases of constness together sounds like a good way forward to me. Regards, Bruce.It seems from the discussion here the past week, there is no real multithreading benefit to be had from const/invariant. 'Pure' is where it's at for that. So maybe we're just better off without the complexities of const. I've certainly gotten used to the lack of const in Python, so why not in a C++-ish language?I start to wonder how much of the "of COURSE we need const!" thinking comes from "if all you have is a hammer, everything starts looking like a nail." That is, I wonder how many people think we absolutely need const because they're so used to using it in C and C++. Never having learned a const-correct language (started with various BASICs, simply don't see the overwhelming need. Sure, there are a very few cases where const could be useful in my code for efficiency's sake, but I've never felt like I was missing any expressive power. Furthermore, I have been bitten exactly once by something that theoretically could have been prevented by const. It took me two minutes in the debugger to track down the problem. I'd say that those two minutes were a much better tradeoff than the god-knows-how-long it'd take to write const and non-const overloads of who-knows-how-many functions.
Sep 17 2007
Bruce Adams Wrote:The problem with this is it isn't easy to tell how many problems would have been prevented if you are a regular user of const because they've been prevented. One exercise to try would be to take a large project and replace const with an empty string and see what the code looks like, then count the number, type and severity of potential errors relating to this absence. The problem is that doesn't take into account the dynamic nature of programming. Far more mistakes occur during development than you might be able to find in a finished product.I think this is a similar argument to the one used to argue that static typing prevents a lot of bugs that dynamic typing might introduce. Many people who have worked in a dynamically-typed language (even on a bigger project) will confess that the gain in productivity of not having to constantly specify interfaces, being able to "blindly" pass things around, etc., create a better cost-to-benefit ratio than static typing. In fact, it's the same argument used to justify checked/specified exceptions in Java. The potential for a bug doesn't mean that that potential will be used, and the productivity benefits of NOT having const might be greater. That strcpy thing _is_ a good example, though it won't catch that many bugs in its usage, since src already needs to be const. But it does show a valid use-case, which is better than I can provide for my argument ;-P.
Sep 17 2007
Robert Fraser Wrote:Bruce Adams Wrote:The same argument can be applied to unit testing and contracts as well but less successfully. Dynamic / scripting languages do let you write code faster but at the expense of potentially being less reliable / robust. C++ is at the other end you over engineer and get reliable robust code - slowly. In an ideal language we could do both. "auto" almost gives us the best of both but we're currently missing an "any" type that would implicitly convert itself as freely as its dynamic language counterpart (at the expense of run-time performance).The problem with this is it isn't easy to tell how many problems would have been prevented if you are a regular user of const because they've been prevented. One exercise to try would be to take a large project and replace const with an empty string and see what the code looks like, then count the number, type and severity of potential errors relating to this absence. The problem is that doesn't take into account the dynamic nature of programming. Far more mistakes occur during development than you might be able to find in a finished product.I think this is a similar argument to the one used to argue that static typing prevents a lot of bugs that dynamic typing might introduce. Many people who have worked in a dynamically-typed language (even on a bigger project) will confess that the gain in productivity of not having to constantly specify interfaces, being able to "blindly" pass things around, etc., create a better cost-to-benefit ratio than static typing. In fact, it's the same argument used to justify checked/specified exceptions in Java.The potential for a bug doesn't mean that that potential will be used, and the productivity benefits of NOT having const might be greater.I agree the case is not proven but unlike static/dynamic typing constness is an option. You can use it or not. In theory you can add it to an implementation as sugar after knocking up a prototype without it. Though, I personally don't advocate that kind of style. I think it is very important to get constness right in the design of interfaces, under the bonnett it matters much less.That strcpy thing _is_ a good example, though it won't catch that many bugs in its usage, since src already needs to be const. But it does show a valid use-case, which is better than I can provide for my argument ;-P.Your toadying will not go unrewarded when I am emperor ;)
Sep 17 2007
Robert Fraser wrote:Bruce Adams Wrote:As an aside, I think that people tend to use one bin for dynamic typing and the auto-instatiation of variables that many dynamically typed languages use (and which is, of course, very evil :-).The problem with this is it isn't easy to tell how many problems would have been prevented if you are a regular user of const because they've been prevented. [...]I think this is a similar argument to the one used to argue that static typing prevents a lot of bugs that dynamic typing might introduce. [...]The potential for a bug doesn't mean that that potential will be used, and the productivity benefits of NOT having const might be greater.It might at least make things simpler, which is a gain in itself. The question is if this outweighs the advantages of having const. Maybe it really *is* time to deconstruct the christmas tree and have a look what kinds of constness are important enough to justify complicating the language by narrowing code freedom. Regards, frank
Sep 17 2007
Bruce Adams a écrit :An example of one that catches me out quite often is: strcpy(src,dest) vs. strcpy(dest,src);If it helps you'not the only one to have this kind of issue: some compilers even try to detect when people makes mistakes for 'memset'? Both case show why function calls with passing the parameter by position instead of by keywords *sucks*. Let's try it: do you think you would make the same mistake if you would call your function this way: char[50] var_dest, my_src; strcpy(dest: var_dest, src: my_src) See? 1) much less risk of errors 2) better readability 3) in case of error, it's easy to see the error and correct it. So there is a better way than const to prevent source/dest error, unfortunately D doesn't support it.. Regards, RenoX
Sep 17 2007
renoX wrote:Bruce Adams a écrit :My eyes... aaarghh! ReganAn example of one that catches me out quite often is: strcpy(src,dest) vs. strcpy(dest,src);If it helps you'not the only one to have this kind of issue: some compilers even try to detect when people makes mistakes for 'memset'? Both case show why function calls with passing the parameter by position instead of by keywords *sucks*. Let's try it: do you think you would make the same mistake if you would call your function this way: char[50] var_dest, my_src; strcpy(dest: var_dest, src: my_src)
Sep 17 2007
Regan Heath wrote:renoX wrote:Is it the particular syntax or the concept you object to? I think named/keyword parameters can be quite useful. Have you ever used a language that has them? I think the problem with putting them into D is only that it becomes yet another way to do things. We already have all the flavors of overloading inherited from C++. --bbBruce Adams a écrit :My eyes... aaarghh!An example of one that catches me out quite often is: strcpy(src,dest) vs. strcpy(dest,src);If it helps you'not the only one to have this kind of issue: some compilers even try to detect when people makes mistakes for 'memset'? Both case show why function calls with passing the parameter by position instead of by keywords *sucks*. Let's try it: do you think you would make the same mistake if you would call your function this way: char[50] var_dest, my_src; strcpy(dest: var_dest, src: my_src)
Sep 17 2007
Bill Baxter Wrote:Regan Heath wrote:Actually I quite like the concept of keywords provided they're optional. I prefer the Fortran-90 syntax: copy(source=foo, dest=bar); since its sort of an assignment. Actually its just as ugly, but you can get used to almost anything eventually. That protects me from one kind of bug where I get source and dest confused. It does not protect me from getting foo and bar confused. If the source is required to be const and foo is not the const variable I am saved. i.e. myfunc( string alpha = var1, string beta = var2 ) { stuff... copy(var2,var1); } vs. myfunc( const string alpha , string beta ) { stuff... copy(source=alpha,dest = beta); } string var1 = "source" string var2; //uninitialised oh no! myfunc(alpha=var1,beta=var2); The const protects me from swapping args when the keywords hide some implementaiton detail. However, agreed positional arguments are a bad thing in general but sometimes necessary. In the above it would be useful to say - must be initialised which in C++ is: const var1 = "source"; Though, a ordinary clever compiler detect that var2 is not initialised without const. So cost benefit analysis so far. Keywords yes, maybe even before const but not a replacement. Regards, Bruce.renoX wrote:Is it the particular syntax or the concept you object to? I think named/keyword parameters can be quite useful. Have you ever used a language that has them? I think the problem with putting them into D is only that it becomes yet another way to do things. We already have all the flavors of overloading inherited from C++. --bbBruce Adams a écrit :My eyes... aaarghh!An example of one that catches me out quite often is: strcpy(src,dest) vs. strcpy(dest,src);If it helps you'not the only one to have this kind of issue: some compilers even try to detect when people makes mistakes for 'memset'? Both case show why function calls with passing the parameter by position instead of by keywords *sucks*. Let's try it: do you think you would make the same mistake if you would call your function this way: char[50] var_dest, my_src; strcpy(dest: var_dest, src: my_src)
Sep 17 2007
Bill Baxter wrote:Regan Heath wrote:Not sure, it just makes my skin crawl at the moment. I've never really had a problem with passing arguments in the wrong order. These days my IDE prompts me as I type, that feature seems to remove the need for this idea completely, to my mind. Granted not every IDE has this. It's a bit like the idea to use 'out'/'ref' 'inout' etc at call site. I can understand the argument that it increases the information available to someone simply reading the code but I just don't want to have to type all that. Again, an IDE could easily display this information for you. But again, not every IDE will have such a feature and if you decided to diplay the source in another form (printed or something) you loose the information again. I guess all I'm saying is that I'm on the other side of the fence, the gain from these additions are less than the cost, to me.renoX wrote:Is it the particular syntax or the concept you object to?Bruce Adams a écrit :My eyes... aaarghh!An example of one that catches me out quite often is: strcpy(src,dest) vs. strcpy(dest,src);If it helps you'not the only one to have this kind of issue: some compilers even try to detect when people makes mistakes for 'memset'? Both case show why function calls with passing the parameter by position instead of by keywords *sucks*. Let's try it: do you think you would make the same mistake if you would call your function this way: char[50] var_dest, my_src; strcpy(dest: var_dest, src: my_src)I think named/keyword parameters can be quite useful. Have you ever used a language that has them?To be fair, no, and I should probably try it before passing judgement. My last post was a 'first impression' or rather, 'another first impression' because I recall this idea being posted before, perhaps several times.I think the problem with putting them into D is only that it becomes yet another way to do things. We already have all the flavors of overloading inherited from C++.That true. Regan
Sep 18 2007
On 9/18/07, Regan Heath <regan netmail.co.nz> wrote:Bill Baxter wrote:Of course, for copying strings in D, we already have the vastly superior syntax dst = src; :-)Regan Heath wrote:Not sure, it just makes my skin crawl at the moment.renoX wrote:Is it the particular syntax or the concept you object to?Bruce Adams a écrit :My eyes... aaarghh!An example of one that catches me out quite often is: strcpy(src,dest) vs. strcpy(dest,src);Let's try it: do you think you would make the same mistake if you would call your function this way: char[50] var_dest, my_src; strcpy(dest: var_dest, src: my_src)
Sep 18 2007
Janice Caron wrote:On 9/18/07, Regan Heath <regan netmail.co.nz> wrote:You mean of course: dst = src.dup ;O)Bill Baxter wrote:Of course, for copying strings in D, we already have the vastly superior syntax dst = src; :-)Regan Heath wrote:Not sure, it just makes my skin crawl at the moment.renoX wrote:Is it the particular syntax or the concept you object to?Bruce Adams a écrit :My eyes... aaarghh!An example of one that catches me out quite often is: strcpy(src,dest) vs. strcpy(dest,src);Let's try it: do you think you would make the same mistake if you would call your function this way: char[50] var_dest, my_src; strcpy(dest: var_dest, src: my_src)
Sep 18 2007
On 9/18/07, Regan Heath <regan netmail.co.nz> wrote:You mean of course: dst = src.dup ;O)Oh yeah! Well spotted. :-)
Sep 18 2007
Regan Heath wrote:Janice Caron wrote:Or: --- dst[] = src; --- to copy to a preallocated buffer (like strcpy does). (Or --- dst[0..src.length] = src; --- if src.length < dst.length...)On 9/18/07, Regan Heath <regan netmail.co.nz> wrote:You mean of course: dst = src.dup ;O)Bill Baxter wrote:Of course, for copying strings in D, we already have the vastly superior syntax dst = src; :-)Regan Heath wrote:Not sure, it just makes my skin crawl at the moment.renoX wrote:Is it the particular syntax or the concept you object to?Bruce Adams a écrit :My eyes... aaarghh!An example of one that catches me out quite often is: strcpy(src,dest) vs. strcpy(dest,src);Let's try it: do you think you would make the same mistake if you would call your function this way: char[50] var_dest, my_src; strcpy(dest: var_dest, src: my_src)
Sep 18 2007
Regan Heath a écrit :Bill Baxter wrote:The IDE can write these thing for you (assuming of course you write the function prototype before the call), and for maintained code, there is more reading/rereading than writing.Regan Heath wrote:Not sure, it just makes my skin crawl at the moment. I've never really had a problem with passing arguments in the wrong order. These days my IDE prompts me as I type, that feature seems to remove the need for this idea completely, to my mind. Granted not every IDE has this. It's a bit like the idea to use 'out'/'ref' 'inout' etc at call site. I can understand the argument that it increases the information available to someone simply reading the code but I just don't want to have to type all that.renoX wrote:Is it the particular syntax or the concept you object to?Bruce Adams a écrit :My eyes... aaarghh!An example of one that catches me out quite often is: strcpy(src,dest) vs. strcpy(dest,src);If it helps you'not the only one to have this kind of issue: some compilers even try to detect when people makes mistakes for 'memset'? Both case show why function calls with passing the parameter by position instead of by keywords *sucks*. Let's try it: do you think you would make the same mistake if you would call your function this way: char[50] var_dest, my_src; strcpy(dest: var_dest, src: my_src)Again, an IDE could easily display this information for you. But again, not every IDE will have such a feature and if you decided to display the source in another form (printed or something) you loose the information again.Yes, that's why having the IDE writing additional information for you is better: everyone benefits from it, whereas if those information are displayed only when you have an IDE, only the users with the IDE will have those information..I guess all I'm saying is that I'm on the other side of the fence, the gain from these additions are less than the cost, to me.As said above, developers spend more time reading code (for debugging, for modifying) than writing code.> I thinkI don't follow you here, having keyword function call doesn't imply that you necessarily allow different a overloading mode.. Sure D could also use the name of the parameters as a disambiguator [which is nice IMHO sin(deg: 90) and sin(rad: pi) is better than sin_deg and sin_rad] but this is not *required*. And IMHO, it wouldn't be wise to add this parameter name overloading at first, because as you said the interactions between this an normal function calls would be weird: in the above example, you wouldn't be able to call sin(5) as the compiler wouldn't be able to distinguish which function is called. renoXnamed/keyword parameters can be quite useful. Have you ever used a language that has them?To be fair, no, and I should probably try it before passing judgement. My last post was a 'first impression' or rather, 'another first impression' because I recall this idea being posted before, perhaps several times.I think the problem with putting them into D is only that it becomes yet another way to do things. We already have all the flavors of overloading inherited from C++.That true. Regan
Sep 18 2007
renoX wrote:Regan Heath a écrit :Which they do using what application ;) The IDE, which can display the specific information each developer finds most useful and can do so without 'cluttering' the source with things another developer may not need/want. ReganI guess all I'm saying is that I'm on the other side of the fence, the gain from these additions are less than the cost, to me.As said above, developers spend more time reading code (for debugging, for modifying) than writing code.
Sep 19 2007
Regan Heath wrote:renoX wrote:Really, not every developer is using some kind of IDE. A syntax highlighting editor is usually enough to feed the compiler. I'm happy that D code is nothing but text, instead of some "enriched" binary junk or junk appended to databases. Best Regards Ingo OeserAs said above, developers spend more time reading code (for debugging, for modifying) than writing code.Which they do using what application ;) The IDE, which can display the specific information each developer finds most useful and can do so without 'cluttering' the source with things another developer may not need/want.
Sep 23 2007
Ingo Oeser Wrote:Regan Heath wrote:But should language features be added to maker reading code easier?renoX wrote:Really, not every developer is using some kind of IDE. A syntax highlighting editor is usually enough to feed the compiler. I'm happy that D code is nothing but text, instead of some "enriched" binary junk or junk appended to databases. Best Regards Ingo OeserAs said above, developers spend more time reading code (for debugging, for modifying) than writing code.Which they do using what application ;) The IDE, which can display the specific information each developer finds most useful and can do so without 'cluttering' the source with things another developer may not need/want.
Sep 23 2007
On Sun, 23 Sep 2007 17:58:34 -0400, Robert Fraser wrote:But should language features be added to maker reading code easier?YES YES YES! (imnsho) Code is examined via more than one method. An IDE is not the only way to look at code. There is email, B&W printers, hand writting, plain text editors, voice (over the telephone), telnet for Bob's sake, etc ... -- Derek Parnell Melbourne, Australia skype: derek.j.parnell
Sep 23 2007
Robert Fraser wrote:But should language features be added to maker reading code easier?Yes. Many projects use domain specific languages to make the code more readable. Very common are table generators. The Linux kernel project uses several enhancements to support checkers while improving readability. One example is endian annotation. You often get data from the network or through some hardware in a specific endianess. You only have to convert that when you start calculating with that stuff or try to hand it out to user space with an API which is defined in native byte order. Since in some networking situations most received stuff can be dropped (e.g. firewall in extremely unfriendly environment), it is wise to defer endian conversion to latest possible. To get all the situations right where we handle native or network byte order, the structure members and function arguments are endian annotated. Now you just need to look at the function signature to get it right. Or run a static checker (like sparse) to check correctness. But really, that stuff is like medicine: The dose matters :-) Best Regards Ingo Oeser
Sep 24 2007
On Mon, 17 Sep 2007 22:57:05 +0100, Regan Heath wrote:renoX wrote:Or ... copy(from: var_dest, to: my_src); -- Derek (skype: derek.j.parnell) Melbourne, Australia 18/09/2007 9:50:52 AMBruce Adams a écrit :My eyes... aaarghh!An example of one that catches me out quite often is: strcpy(src,dest) vs. strcpy(dest,src);If it helps you'not the only one to have this kind of issue: some compilers even try to detect when people makes mistakes for 'memset'? Both case show why function calls with passing the parameter by position instead of by keywords *sucks*. Let's try it: do you think you would make the same mistake if you would call your function this way: char[50] var_dest, my_src; strcpy(dest: var_dest, src: my_src)
Sep 17 2007
On Tue, 18 Sep 2007 09:52:46 +1000, Derek Parnell wrote:On Mon, 17 Sep 2007 22:57:05 +0100, Regan Heath wrote:P.S. This still doesn't remove the usefulness of 'const' concept though. For example .. copy(from: ExampleA, to: ExampleB); This line by itself doesn't tell the reader if 'ExampleB' is writeable or not. -- Derek (skype: derek.j.parnell) Melbourne, Australia 18/09/2007 11:04:23 AMrenoX wrote:Or ... copy(from: var_dest, to: my_src);Bruce Adams a écrit :My eyes... aaarghh!An example of one that catches me out quite often is: strcpy(src,dest) vs. strcpy(dest,src);If it helps you'not the only one to have this kind of issue: some compilers even try to detect when people makes mistakes for 'memset'? Both case show why function calls with passing the parameter by position instead of by keywords *sucks*. Let's try it: do you think you would make the same mistake if you would call your function this way: char[50] var_dest, my_src; strcpy(dest: var_dest, src: my_src)
Sep 17 2007
"renoX" <renosky free.fr> wrote in message news:fcmsmv$1drt$1 digitalmars.com...strcpy(dest: var_dest, src: my_src)My eyes... ahhhh! They feel so good having seen such self-explanatory code. Code that reads close to natural language == win, as far as I'm concerned.
Sep 17 2007
Lionello Lunesu Wrote:void bar() throw; void foo() { bar(); }//ERROR, bar can throw void foo2() throw { bar(); } //OK void foo3() throw { bar() throw; } //OK ("cast")In other words, all exceptions are checked exceptions...? This would especially be a problem since all allocations can throw exceptions unless caught. This sounds like it would introduce MORE problems than Java's checked exceptions. I think the "safe" case sis typically the marked one (i.e. Walter's "nothrow" he mentioned at the conference, const, pure, etc.). The whole red code-green code idea isn't bad, but I think that should generally be relegated to documentation instead of making the compiler check it. There seems to be a general push (among many computer scientists) to enforce stricter rules, yet some of the most successful languages in the past few years have been dynamically/duck typed. The price is that the impetus of using the code correctly falls on the programmer and not the compiler/interpreter. The reward is much greater productivity, since the programmer doesn't need to be concerned about such things as const-correctness, checked exceptions or interface specification, she just works with the knowledge the compiler trusts her enough to do the right thing. I'm not suggesting D go dynamically-typed (doesn't work so well in a compiled language), but restrictions for the sake of restrictions should be looked upon with great care. If const or pure can help optimization and make paralell programming easier, I'm all for it, but if it'll just sit there and make my life harder then it's not worth it. I'd like to pose a question to those who have used C++'s const: do you feel that it has saved more time by preventing bugs than it has taken by being forced to type it all the time, and the time spent when it has to be removed all throughout a hierarchy, as inevitably has to happen at least once? That is, const-correctness is a time investment, so do you feel that investment has paid off for you? I can say that working in Java, I have _never_ felt that if I pass a class reference that was "constant" in nature to a method written by somebody else or even to entirely different subsystem, that the invariantness contract, specified only in the documentation, would be broken. Compiler checks in that case end up being as useless and annoying as checked exceptions.
Sep 17 2007
"Robert Fraser" <fraserofthenight gmail.com> wrote in message news:fcmngv$qhq$1 digitalmars.com...I'm not suggesting D go dynamically-typed (doesn't work so well in a compiled language),Bit of a sidetrack here. Dynamic typing, in the sense that variables don't have types, certainly doesn't go well in a compiled language, but type inference, something that ends up looking very similar to dynamic typing, _does_, can, and has been implemented well in compiled languages. ML and Haskell are examples. Nemerle as well, because even though it compiles to a VM it's still a statically typed VM. It's almost like IFTI or variable declaration type inference (auto x = 5), but extended to virtually _everything_. One language I've seen that I really liked was Bla. It uses Haskell-style type inference, but it still allows you to explicitly type things if you want. In this way you can do away with typing variables/params in a vast majority of the cases, and in the instances when you _want_ something to be typed, or when the type inference system can't figure it out on its own, you can type it manually. Of course something like this would probably be far too much of a departure for a language like D.
Sep 17 2007
Jarrett Billingsley wrote:One language I've seen that I really liked was Bla. It uses Haskell-style type inference, but it still allows you to explicitly type things if you want. In this way you can do away with typing variables/params in a vast majority of the cases, and in the instances when you _want_ something to be typed, or when the type inference system can't figure it out on its own, you can type it manually. Of course something like this would probably be far too much of a departure for a language like D.Of course type systems aren't one dimensional - there can be several kinds of implicit static typing too. I had an impression that the lack of type inference in some places is only temporary. I agree that some advanced type techniques involving a Turing complete compile time language are not exactly what the users are expecting. Heh, they might be in the future, but let's not tell anyone - D still has reputation being a "practical language" for "real world tasks".
Sep 17 2007
Robert Fraser wrote:Lionello Lunesu Wrote: There seems to be a general push (among many computer scientists) to enforce stricter rules, yet some of the most successful languages in the past few years have been dynamically/duck typed.Note however that as these languages mature people are gradually trying to put some notion of interface-checking back in. I only really know about python, but there we have pyprotocols (http://peak.telecommunity.com/PyProtocols.html) and zope.interface (http://www.zope.org/Products/ZopeInterface) that both aim to put some non-duck type checking features back into the language. Because, surprise, when you're scaling up to huge systems it becomes difficult to figure out exactly what kind of duck you're supposed to be passing.I'd like to pose a question to those who have used C++'s const: do you feel that it has saved more time by preventing bugs than it has taken by being forced to type it all the time, and the time spent when it has to be removed all throughout a hierarchy, as inevitably has to happen at least once? That is, const-correctness is a time investment, so do you feel that investment has paid off for you?That's kind of why I started this thread. I started using C++ in 1995 and it has been my main language since about 1998. I'm very used to C++'s const. But I do vaguely recall finding it terribly annoying in 1995 when I started moving over from C. The C++ people kept telling me that const correctness was like eating your peas. "You may not like it, but it's good for you." And now I like const, just like I like eating peas now too. It's not that I prefer the taste of peas to chocolate ice cream, but if I don't eat my peas I get this feeling like my health may fall apart at any minute. It's the same feeling I get from not using const. That said, I can program in Python without const and not flinch at all. Because const correctness is just not a part of Python. There are no peas in Python-land so I don't feel like I have to eat them. It's ice cream for every meal! Of course in Python-land "slow" has also been declared the new "fast", so I also don't flinch about making heap allocations willy-nilly.I can say that working in Java, I have _never_ felt that if I pass a class reference that was "constant" in nature to a method written by somebody else or even to entirely different subsystem, that the invariantness contract, specified only in the documentation, would be broken. Compiler checks in that case end up being as useless and annoying as checked exceptions.Here's the one case that makes me want const: Efficient vector math. Say you're writing a routine to compute whether or not three points are inside the circumcircle defined by three others. Here's how I wrote it in D: // Return if point d is in the circumcircle defined by points a,b,c. // The points a,b,c should be given in counter-clockwise order. bool in_circle(Point a, Point b, Point c, ref Point d) { a -= d; b -= d; c -= d; assert(is_CCW(a,b,c), "input circle points are not in ccw order"); Scalar a2 = a.sqrnorm(); Scalar b2 = b.sqrnorm(); Scalar c2 = c.sqrnorm(); Scalar det = a2*(b.x*c.y - b.y*c.x) + b2*(a.y*c.x - a.x*c.y) + c2*(a.x*b.y - a.y*b.x); return det >= 0; } Really I would like to make 'ref Point d' there be const. I'm passing it by reference because it's slightly more efficient and in_circle can get called a *lot*. I go ahead and pass a,b,c by value because I'm going to have to push a copy on the stack to modify them anyway. If I weren't modifying them I'd pass them by reference, too. But those are implementation details that the caller of in_circle doesn't really care about. So it's odd they should be in the interface. Ref/const ref is not a very direct solution for this kind of need. What i'd really like to be able to do is declare the function to be generically non-mutating (like 'in'), but at the same time time a) allow the implementation to modify its arguments if it wants to and b) make the call using the most efficient mechanism possible. I don't really want to have to guess whether the argument is big enough to justify pass by reference or not. It probably depends a lot on the architecture and number of accesses to the variable actually made in the end. Just using plain 'ref' would maybe be an acceptable solution, except you can't pass literals by ref. So if you make a min template like "T min(T)(ref T a, ref T b) {...};" min(0,x) won't compile. That's just too useful to disallow. And then if T is a class type then it's already a reference so there's not need to take a reference to the reference. You can work around these things with lots of static if(is(T==class)) type things, but it gets ugly fast. It would be great if something like T min(T)(in T a, in T b) {...} "just worked". I.e. prevented visible modifications to a,b but didn't do unnecessary, inefficient copying of big structures, and didn't take unnecessary references of arguments that are already references, and allowed calling with literals. Give me a way to do that and I'll be happy. I'd even be willing to ditch the 'prevent modifications' bit as long as I can have efficiency and the ability to pass constants. --bb
Sep 17 2007
Bill Baxter Wrote:Robert Fraser wrote:So in other words the duck stops here ;)Lionello Lunesu Wrote: There seems to be a general push (among many computer scientists) to enforce stricter rules, yet some of the most successful languages in the past few years have been dynamically/duck typed.Note however that as these languages mature people are gradually trying to put some notion of interface-checking back in. I only really know about python, but there we have pyprotocols (http://peak.telecommunity.com/PyProtocols.html) and zope.interface (http://www.zope.org/Products/ZopeInterface) that both aim to put some non-duck type checking features back into the language. Because, surprise, when you're scaling up to huge systems it becomes difficult to figure out exactly what kind of duck you're supposed to be passing.
Sep 18 2007
Bill Baxter Wrote:Robert Fraser wrote:Showing my true colours as a D noob here. I thought that with D like in java any object argument is passed by reference by default but unlike java the D compiler has the option of passing by value if it decides it would be more efficient. A const declaration here would help that. I believe it should be down to the compiler to decide when to do this because it makes no visible difference from the programmers perspective. constness is part of the contract but perhaps allowing copy on write where you want to modify arguments is an option. It may be a dangerous one because it allows you to shoot yourself in the foot and modify a variable thinking you are modifying the real one when actually you are only modifying a local copy. The inverse of the normal problem. Bruce.Lionello Lunesu Wrote: There seems to be a general push (among many computer scientists) to enforce stricter rules, yet some of the most successful languages in the past few years have been dynamically/duck typed.Note however that as these languages mature people are gradually trying to put some notion of interface-checking back in. I only really know about python, but there we have pyprotocols (http://peak.telecommunity.com/PyProtocols.html) and zope.interface (http://www.zope.org/Products/ZopeInterface) that both aim to put some non-duck type checking features back into the language. Because, surprise, when you're scaling up to huge systems it becomes difficult to figure out exactly what kind of duck you're supposed to be passing.I'd like to pose a question to those who have used C++'s const: do you feel that it has saved more time by preventing bugs than it has taken by being forced to type it all the time, and the time spent when it has to be removed all throughout a hierarchy, as inevitably has to happen at least once? That is, const-correctness is a time investment, so do you feel that investment has paid off for you?That's kind of why I started this thread. I started using C++ in 1995 and it has been my main language since about 1998. I'm very used to C++'s const. But I do vaguely recall finding it terribly annoying in 1995 when I started moving over from C. The C++ people kept telling me that const correctness was like eating your peas. "You may not like it, but it's good for you." And now I like const, just like I like eating peas now too. It's not that I prefer the taste of peas to chocolate ice cream, but if I don't eat my peas I get this feeling like my health may fall apart at any minute. It's the same feeling I get from not using const. That said, I can program in Python without const and not flinch at all. Because const correctness is just not a part of Python. There are no peas in Python-land so I don't feel like I have to eat them. It's ice cream for every meal! Of course in Python-land "slow" has also been declared the new "fast", so I also don't flinch about making heap allocations willy-nilly.I can say that working in Java, I have _never_ felt that if I pass a class reference that was "constant" in nature to a method written by somebody else or even to entirely different subsystem, that the invariantness contract, specified only in the documentation, would be broken. Compiler checks in that case end up being as useless and annoying as checked exceptions.Here's the one case that makes me want const: Efficient vector math. Say you're writing a routine to compute whether or not three points are inside the circumcircle defined by three others. Here's how I wrote it in D: // Return if point d is in the circumcircle defined by points a,b,c. // The points a,b,c should be given in counter-clockwise order. bool in_circle(Point a, Point b, Point c, ref Point d) { a -= d; b -= d; c -= d; assert(is_CCW(a,b,c), "input circle points are not in ccw order"); Scalar a2 = a.sqrnorm(); Scalar b2 = b.sqrnorm(); Scalar c2 = c.sqrnorm(); Scalar det = a2*(b.x*c.y - b.y*c.x) + b2*(a.y*c.x - a.x*c.y) + c2*(a.x*b.y - a.y*b.x); return det >= 0; } Really I would like to make 'ref Point d' there be const. I'm passing it by reference because it's slightly more efficient and in_circle can get called a *lot*. I go ahead and pass a,b,c by value because I'm going to have to push a copy on the stack to modify them anyway. If I weren't modifying them I'd pass them by reference, too. But those are implementation details that the caller of in_circle doesn't really care about. So it's odd they should be in the interface. Ref/const ref is not a very direct solution for this kind of need. What i'd really like to be able to do is declare the function to be generically non-mutating (like 'in'), but at the same time time a) allow the implementation to modify its arguments if it wants to and b) make the call using the most efficient mechanism possible. I don't really want to have to guess whether the argument is big enough to justify pass by reference or not. It probably depends a lot on the architecture and number of accesses to the variable actually made in the end. Just using plain 'ref' would maybe be an acceptable solution, except you can't pass literals by ref. So if you make a min template like "T min(T)(ref T a, ref T b) {...};" min(0,x) won't compile. That's just too useful to disallow. And then if T is a class type then it's already a reference so there's not need to take a reference to the reference. You can work around these things with lots of static if(is(T==class)) type things, but it gets ugly fast. It would be great if something like T min(T)(in T a, in T b) {...} "just worked". I.e. prevented visible modifications to a,b but didn't do unnecessary, inefficient copying of big structures, and didn't take unnecessary references of arguments that are already references, and allowed calling with literals. Give me a way to do that and I'll be happy. I'd even be willing to ditch the 'prevent modifications' bit as long as I can have efficiency and the ability to pass constants. --bb
Sep 18 2007
Robert Fraser wrote:I'd like to pose a question to those who have used C++'s const: do you feel that it has saved more time by preventing bugs than it has taken by being forced to type it all the time, and the time spent when it has to be removed all throughout a hierarchy, as inevitably has to happen at least once? That is, const-correctness is a time investment, so do you feel that investment has paid off for you?At the upcoming http://www.astoriaseminar.com, I think I'll do some asking around on this issue. There'll be a lot of C++ diehards there.I can say that working in Java, I have _never_ felt that if I pass a class reference that was "constant" in nature to a method written by somebody else or even to entirely different subsystem, that the invariantness contract, specified only in the documentation, would be broken.Some Java professionals have reported problems with not being able to specify const classes. These people work on Java programs with large teams.Compiler checks in that case end up being as useless and annoying as checked exceptions.I don't think that's the same issue. The problem with checked exceptions is that suppose you have functions A, B, C, where A calls B, and B calls C. Now, you throw a new exception in C, and catch it in A. Arggh, you've got to change B.
Sep 17 2007
Walter Bright Wrote:Robert Fraser wrote:I work (well, intern...) on a Java project with a team of ~35 developers. Can't say I've ever really wanted to constify something, although needing to synchronize everything when in doubt does get annoying (and as I keep telling my boss hurts performance dramatically, but they're big fans of the "throw more hardware at it" form of performance refactoring) so knowing something is INVARIANT might occasionally be helpful. But as a purely interface thing, I think docs serve better.I'd like to pose a question to those who have used C++'s const: do you feel that it has saved more time by preventing bugs than it has taken by being forced to type it all the time, and the time spent when it has to be removed all throughout a hierarchy, as inevitably has to happen at least once? That is, const-correctness is a time investment, so do you feel that investment has paid off for you?At the upcoming http://www.astoriaseminar.com, I think I'll do some asking around on this issue. There'll be a lot of C++ diehards there.I can say that working in Java, I have _never_ felt that if I pass a class reference that was "constant" in nature to a method written by somebody else or even to entirely different subsystem, that the invariantness contract, specified only in the documentation, would be broken.Some Java professionals have reported problems with not being able to specify const classes. These people work on Java programs with large teams.Same with const, but top-down. Make something const in A, you have to make it const in B and C. If you ague that if B and C weren't changing it, then what if C's implementation changed in such a way as it dos make a change. Now, arrgh, got to go back and change it in B and A. It's not nearly as bad as checked exceptions, but const for const's sake is excessive and useless. Hopefully, though, IDEs will be able to do it all for you (Descent will get there someday!).Compiler checks in that case end up being as useless and annoying as checked exceptions.I don't think that's the same issue. The problem with checked exceptions is that suppose you have functions A, B, C, where A calls B, and B calls C. Now, you throw a new exception in C, and catch it in A. Arggh, you've got to change B.
Sep 17 2007
Robert Fraser wrote:But as a purely interface thing, I think docs serve better.The problem with docs is they are invariably wrong, out of date, ambiguous, or missing. Docs are also unreadable by analysis tools, and can't be relied upon by code auditors.Same with const, but top-down. Make something const in A, you have to make it const in B and C.Only if B and C were done poorly to begin with, and didn't already say they didn't change the reference.If you ague that if B and C weren't changing it, then what if C's implementation changed in such a way as it dos make a change. Now, arrgh, got to go back and change it in B and A.But that is a *relevant* change. The exception passthrough is not relevant, as it means nothing to B.
Sep 18 2007
On 9/18/07, Walter Bright <newshound1 digitalmars.com> wrote:Robert Fraser wrote:The issues in C++ aren't necessarily the same as the issues in D, however. Perhaps the most significant thing is that in C++, all classes are passed by value by default. That means that function parameters are essentially const by default, because the function gets its own copy of the object rather than referencing the original. To pass by pointer or reference, you must explicitly code it to do that, and only then does const start to creep in. This can lead to some very awkward coding practices, e.g. void f(std::string const & s); ...which basically does exactly the same job as void f(std::string s) Obviously you don't need "const" in the latter case because you're passing by value, but as soon as you start passing by reference (for efficiency - it avoids unnecessary copy constructor and destructor calls) you suddenly start to need const. In D, things are a bit different, because (as in Java) classes are passed by reference, and that means that the const keyword is going to be needed a lot more. An alternative approach might be to have reference types passed to functions as const by default, requiring the function author to explicitly state (by means of the ref keyword) that the object is mutable. This would mean that classes would then have exactly the same semantics as structs. e.g. struct S; class C; void f(S s); /* f gets a copy of s, so cannot modify the original */ void f(ref S s); /* s passed by reference, so f can modify it */ void f(C c); /* s passed by const reference, so f cannot modify it */ void f(ref C c); /* s passed by reference-to-mutable, so f can modify it */ Of course, this brings us back to the head/tail const distinction. In the above examples, we are only concerned with the constness of the object's members. In the fourth example, we arrive at a situation which /can never happen in C++/, because in C++, references are /always/ head-const. That is: void f(C & c) { s = new C(); /*ERROR - c is a reference */ } will not compile, because even though c was not declared as const, it is nonetheless head-const /because it is a reference/ This leads me to my second thought (I have more...), which is the notion that all function parameters should be head-const, not just by default, but absolutely. This would support all of the preceeding argument, but it would also mean that, for example void f(int n) { ++n; /* Error */ } would no longer compile. That's not the end of the world, because n is local anyway. The only change the programmer would need make to their code is to make a local copy of n, like this: void f(int n0) { n = n0; /* local copy - may modify */ ++n; /* OK */ } which brings me to my third and final observation, which is that this scheme needs one final "fix" before it becomes usable, because, as I've described it above, structs would be passed by value, and yet the function would not be able to modify them. And obviously that's bad. So here's the final trick to make it all hunky dory. For value types, such as structs or ints, we (that is, the compiler), divide them into two categories: Category A consists of all primitive types, and all structs which are less than some threshold size (say, 16 bytes). Category B consists of all remaining structs. In summary, category = (T.sizeof < 16) ? "A" : "B". Category A objects are passed by value. Category B objects are passed by reference. Some examples would help explain: --------------------------- struct SmallStruct { int x; int y; } SmallStruct s; f(s); void f(SmallStruct s) /* s is passed by value and is head-const */ { s.x = 3; /* Error - s is head-const */ SmallStruct s2 = s; s2.x = 3; /* OK */ } void g(ref BigStruct s) /* s is passed by reference and is head-const */ { s.x = 3; /* OK */ } --------------------------- struct BigStruct { int x; int[100] y; } SmallStruct s; f(s); void f(BigStruct s) /* s is passed by reference and is head-const and tail-const */ { s.x = 3; /* Error - s is tail-const */ SmallStruct s2 = s; s2.x = 3; /* OK */ } void g(ref BigStruct s) /* s is passed by reference and is head-const */ { s.x = 3; /* OK */ } --------------------------- class MyClass { int x; int y; } MyClass s; f(s); void f(MyClass s) /* s is already a reference, which passed by copy, but we consider it head-const and tail-const */ { s = new MyClass; /* Error - s is head-const */ s.x = 3; /* Error - s is tail-const */ MyClass s2 = s.dup; s2.x = 3; /* OK */ } void g(ref MyClass s) /* s is already a reference, which passed by copy, but we consider it head-const */ { s = new MyClass; /* Error - s is head-const */ s.x = 3; /* OK */ } --------------------------- The important thing to observe in these examples is that everything works the same - the semantics are identical at both the caller site and the callee site. The second important thing to observe is that the word "const" is completely absent from these examples. If you have const-by-default, you don't need it. Instead, you work around head-constness by making a local copy, and you override tail-constness by using the "ref" keyword. Plus - you get built-in effeciency for passing large structs to functions. I believe that this will help programmers to write code quickly without having to remember to write "const" all over the place. If they need to modify the original, the compiler will remind them to throw in a "ref" keyword to make it explicit. Everyone wins. It's easy to write code, and the compiler gets to do its checking.I'd like to pose a question to those who have used C++'s const: do you feel that it has saved more time by preventing bugs than it has taken by being forced to type it all the time, and the time spent when it has to be removed all throughout a hierarchy, as inevitably has to happen at least once? That is, const-correctness is a time investment, so do you feel that investment has paid off for you?At the upcoming http://www.astoriaseminar.com, I think I'll do some asking around on this issue. There'll be a lot of C++ diehards there.
Sep 18 2007
About passing structs by reference: It's one of those things, like register or inline... Once upon a time, programmers used the keyword "register" because they thought they could do a better job than the compiler at figuring how to use its registers. Once upon a time, programmers used the keyword "inline" because they thought they could do a better job than the compiler at figuring out what to inline and what not. Now people explicitly choose between f(s) and f(ref s) (where s is a struct and the function does not modify it) because they think they can do a better job than the compiler at figuring out how to pass parameters to functions. I say give control back to the compiler. Lets let "ref" mean "the function may modify the parameter", and the absense of ref mean "the function may not modify the parameter", but leave it to the compiler to decide what is the most efficient way to pass the data to the function. I think this is a neat idea, however it won't work unless the compiler can also do const-checking. This is one more optimisation which having const allows. (And const-by-default would make it obvious). ---- I have thought of a problem though. Under the scheme I outlined in a previous post, it would no longer be possible for a function to modify the original reference. That is: class C; C c; f(c) void f(ref C c) { c = new C(); /* compile-time error */ } would no longer compile, because under the new scheme, "ref" is reinterpreted to mean that c is head-const (because C is a class - see definitions in previous post). So instead, you'd have to do: class C; C c; f(&c) void f(ref C* c) { *c = new C(); } Whether or not that would be considered a prohibiting problem, I don't know.
Sep 18 2007
Janice Caron wrote:About passing structs by reference: It's one of those things, like register or inline... Once upon a time, programmers used the keyword "register" because they thought they could do a better job than the compiler at figuring how to use its registers. Once upon a time, programmers used the keyword "inline" because they thought they could do a better job than the compiler at figuring out what to inline and what not. Now people explicitly choose between f(s) and f(ref s) (where s is a struct and the function does not modify it) because they think they can do a better job than the compiler at figuring out how to pass parameters to functions. I say give control back to the compiler. Lets let "ref" mean "the function may modify the parameter", and the absense of ref mean "the function may not modify the parameter", but leave it to the compiler to decide what is the most efficient way to pass the data to the function.This thought has occurred to me before to. I think issue becomes that the function signature may no longer enough for a compiler to tell what kind of code it needs to generate to call the function. So for instance "pass by ref unless something in the function modifies the value" is not going to work. But something like "pass by value unless the size of the parameter is greater than 8 bytes" could work. I think this is a separate issue from explicitly passing things as 'ref'. The above seems more appropriate to me as an implementation of 'in' parameters. For compiling function bodies, if the compiler detects a modification of an 'in' parameter that it chose to implement using pass-by-reference then it would just generate code in the function body to copy the parameter value first first thing. E.g. void foo(in BigStruct x); compiler actually generates code like: void foo(ref BigStruc x) { ... } unless the body of foo modifies x. Then the code gen changes to: void foo(ref BigStruct x_) { BigStruct x = x_; ... } There would still be a bit of a compiler compatibility issue though. For a given platform Compiler vendors A and B would need to agree on the rules for 'in' parameters or the libs they generate would be incompatible. If we want D to be a language with a unified ABI at least. That suggests that the rules would need to be part of the spec. Heck it may be good enough to just pick a max parameter size and stick with it for all platforms. Just like D picks a size for 'float' and sticks with it for all platforms, whether it's the most efficient for that platform or not. --bb
Sep 18 2007
On 9/18/07, Bill Baxter <dnewsgroup billbaxter.com> wrote:This thought has occurred to me before to. I think issue becomes that the function signature may no longer enough for a compiler to tell what kind of code it needs to generate to call the function.That is also true for inline. I believe the solution for the pass-by-ref vs pass-by-value decision is that the compiler generates both versions of the function, and then may throw one of them away at link-time.
Sep 18 2007
Janice Caron wrote:On 9/18/07, Bill Baxter <dnewsgroup billbaxter.com> wrote:So the compiler generates 2^N versions for an N-parameter method? --bbThis thought has occurred to me before to. I think issue becomes that the function signature may no longer enough for a compiler to tell what kind of code it needs to generate to call the function.That is also true for inline. I believe the solution for the pass-by-ref vs pass-by-value decision is that the compiler generates both versions of the function, and then may throw one of them away at link-time.
Sep 18 2007
On 9/18/07, Bill Baxter <dnewsgroup billbaxter.com> wrote:So the compiler generates 2^N versions for an N-parameter method?Still only two ... I /think/ The first version is the version in which all information is known. This is the version in which optimal decisions are assumed at the callee site, and may be taken at the caller site. The second version is the version in which no information is known. In this version, everything gets passed by the default behaviour. So, at the callee site, either all information about the function is known, in which case we call version A, or it isn't in which case we call version B. I think that would work. It may not be /quite/ as efficient as the 2^N possibility you mentioned, but it would certainly be more efficient than the status quo (version B for everything).
Sep 18 2007
Janice Caron wrote:On 9/18/07, Bill Baxter <dnewsgroup billbaxter.com> wrote:That makes sense and seems like it could work if you have const refs to use as the fallback. Otherwise the fallback is going to be pass-by-value, which would be terrible for any BigStruct parameters. Object files would unfortunately just about double in size overnight... --bbSo the compiler generates 2^N versions for an N-parameter method?Still only two ... I /think/ The first version is the version in which all information is known. This is the version in which optimal decisions are assumed at the callee site, and may be taken at the caller site. The second version is the version in which no information is known. In this version, everything gets passed by the default behaviour.
Sep 18 2007
Bill Baxter wrote:Janice Caron wrote:No, just for the cases, where it really matters in code size and/or speed. Isn't that kind of optimisation called "function versioning" in compiler folk slang? Once you compile in project global scope, you can do a lot of fun stuff. The problem is: We usually don't compile code that way :-( Best Regards Ingo OeserOn 9/18/07, Bill Baxter <dnewsgroup billbaxter.com> wrote:So the compiler generates 2^N versions for an N-parameter method?This thought has occurred to me before to. I think issue becomes that the function signature may no longer enough for a compiler to tell what kind of code it needs to generate to call the function.That is also true for inline. I believe the solution for the pass-by-ref vs pass-by-value decision is that the compiler generates both versions of the function, and then may throw one of them away at link-time.
Sep 18 2007
On 9/18/07, Bill Baxter <dnewsgroup billbaxter.com> wrote:Janice Caron wrote:Actually, I think it's possible my proposal may not have been understood. Under my suggestion, if the caller passes a struct... f(s) ...and the callee declares the function as... void f(S s) ...then all information is known. Both ends must surely know s.sizeof at compile time? And since that's the /only/ thing the compiler needs to know to make the decision.About passing structs by reference: It's one of those things, like register or inline... Once upon a time, programmers used the keyword "register" because they thought they could do a better job than the compiler at figuring how to use its registers. Once upon a time, programmers used the keyword "inline" because they thought they could do a better job than the compiler at figuring out what to inline and what not. Now people explicitly choose between f(s) and f(ref s) (where s is a struct and the function does not modify it) because they think they can do a better job than the compiler at figuring out how to pass parameters to functions. I say give control back to the compiler. Lets let "ref" mean "the function may modify the parameter", and the absense of ref mean "the function may not modify the parameter", but leave it to the compiler to decide what is the most efficient way to pass the data to the function.This thought has occurred to me before to. I think issue becomes that the function signature may no longer enough for a compiler to tell what kind of code it needs to generate to call the function.So for instance "pass by ref unless something in the function modifies the value" is not going to work.Agreed. But that's not what I suggested. You'd probably have to head back to see the earlier post to see the suggestion in full, because it's too long to repost, but basically it all works (...or at least, I think so...) providing you have parameters passed as const by default, which is an argument in favor of needing const. (If this discussion gets too complicated, we can take it to another thread)
Sep 18 2007
Janice Caron wrote:On 9/18/07, Bill Baxter <dnewsgroup billbaxter.com> wrote:Yeh, sorry my response was more along the lines of "that's an interesting idea that reminds me of this idea *I* had". Your idea requires const by default, but unfortunately const by default has been beaten to death around here. Nearly everyone who cares about D lobbied for giving it a try as Walter was designing const for D2.0, but in the end Walter said, no, it's too big a departure from C++. --bbJanice Caron wrote:Actually, I think it's possible my proposal may not have been understood. Under my suggestion, if the caller passes a struct... f(s) ...and the callee declares the function as... void f(S s) ...then all information is known. Both ends must surely know s.sizeof at compile time? And since that's the /only/ thing the compiler needs to know to make the decision.About passing structs by reference: It's one of those things, like register or inline... Once upon a time, programmers used the keyword "register" because they thought they could do a better job than the compiler at figuring how to use its registers. Once upon a time, programmers used the keyword "inline" because they thought they could do a better job than the compiler at figuring out what to inline and what not. Now people explicitly choose between f(s) and f(ref s) (where s is a struct and the function does not modify it) because they think they can do a better job than the compiler at figuring out how to pass parameters to functions. I say give control back to the compiler. Lets let "ref" mean "the function may modify the parameter", and the absense of ref mean "the function may not modify the parameter", but leave it to the compiler to decide what is the most efficient way to pass the data to the function.This thought has occurred to me before to. I think issue becomes that the function signature may no longer enough for a compiler to tell what kind of code it needs to generate to call the function.So for instance "pass by ref unless something in the function modifies the value" is not going to work.Agreed. But that's not what I suggested. You'd probably have to head back to see the earlier post to see the suggestion in full, because it's too long to repost, but basically it all works (...or at least, I think so...) providing you have parameters passed as const by default, which is an argument in favor of needing const. (If this discussion gets too complicated, we can take it to another thread)
Sep 18 2007
Janice Caron Wrote:On 9/18/07, Bill Baxter <dnewsgroup billbaxter.com> wrote:S could be an opaque type so s.sizeof may still be undefined. Bruce.Janice Caron wrote:Actually, I think it's possible my proposal may not have been understood. Under my suggestion, if the caller passes a struct... f(s) ...and the callee declares the function as... void f(S s) ...then all information is known. Both ends must surely know s.sizeof at compile time? And since that's the /only/ thing the compiler needs to know to make the decision.About passing structs by reference: It's one of those things, like register or inline... Once upon a time, programmers used the keyword "register" because they thought they could do a better job than the compiler at figuring how to use its registers. Once upon a time, programmers used the keyword "inline" because they thought they could do a better job than the compiler at figuring out what to inline and what not. Now people explicitly choose between f(s) and f(ref s) (where s is a struct and the function does not modify it) because they think they can do a better job than the compiler at figuring out how to pass parameters to functions. I say give control back to the compiler. Lets let "ref" mean "the function may modify the parameter", and the absense of ref mean "the function may not modify the parameter", but leave it to the compiler to decide what is the most efficient way to pass the data to the function.This thought has occurred to me before to. I think issue becomes that the function signature may no longer enough for a compiler to tell what kind of code it needs to generate to call the function.
Sep 18 2007
Bruce Adams wrote:Janice Caron Wrote:On 9/18/07, Bill Baxter <dnewsgroup billbaxter.com> wrote:Janice Caron wrote:Actually, I think it's possible my proposal may not have been understood. Under my suggestion, if the caller passes a struct... f(s) ...and the callee declares the function as... void f(S s) ...then all information is known. Both ends must surely know s.sizeof at compile time? And since that's the /only/ thing the compiler needs to know to make the decision.About passing structs by reference: It's one of those things, like register or inline... Once upon a time, programmers used the keyword "register" because they thought they could do a better job than the compiler at figuring how to use its registers. Once upon a time, programmers used the keyword "inline" because they thought they could do a better job than the compiler at figuring out what to inline and what not. Now people explicitly choose between f(s) and f(ref s) (where s is a struct and the function does not modify it) because they think they can do a better job than the compiler at figuring out how to pass parameters to functions. I say give control back to the compiler. Lets let "ref" mean "the function may modify the parameter", and the absense of ref mean "the function may not modify the parameter", but leave it to the compiler to decide what is the most efficient way to pass the data to the function.This thought has occurred to me before to. I think issue becomes that the function signature may no longer enough for a compiler to tell what kind of code it needs to generate to call the function.S could be an opaque type so s.sizeof may still be undefined.You can't declare a function that takes an argument of unknown size. You just can't. The compiler will complain that it doesn't know the type. So either your "opaque type" is not allowable, or it's actually a reference/pointer to "opaque type" in which case the size of the pointer *is* known, which is all that is needed, since that's all that will be passed to the function. --bb
Sep 18 2007
Bill Baxter Wrote:Bruce Adams wrote:See my reply to Janice on channel B. I did mean its passed by reference. I don't quite get the structs are passed by value by default thing. I'm assuming everything is passed by reference by default but that sometimes you want the compiler to pass by value as for small data types by they classes or structs its more efficient. So my point is that for an opaque type you may not have access to sizeof. An opaque type is like a class or struct whose data members are all private but done properly. You don't need to know about the implementation. C++ forces you to expose the implementation by declaring the members in the header even though they're private and client code can't do anything with them. The caveat is you do still need to know the size to reserve space for an opaque type before its constructed. This is why a C++ compiler needs a full definition. In theory it could be sorted at link time with support from the object file format or even left until run-time. My understanding was that you can do opaque types properly in D though I haven't tried myself. So you have sizeof at link time but not necessarily at compile time. Regards, Bruce.Janice Caron Wrote:On 9/18/07, Bill Baxter <dnewsgroup billbaxter.com> wrote:Janice Caron wrote:Actually, I think it's possible my proposal may not have been understood. Under my suggestion, if the caller passes a struct... f(s) ...and the callee declares the function as... void f(S s) ...then all information is known. Both ends must surely know s.sizeof at compile time? And since that's the /only/ thing the compiler needs to know to make the decision.About passing structs by reference: It's one of those things, like register or inline... Once upon a time, programmers used the keyword "register" because they thought they could do a better job than the compiler at figuring how to use its registers. Once upon a time, programmers used the keyword "inline" because they thought they could do a better job than the compiler at figuring out what to inline and what not. Now people explicitly choose between f(s) and f(ref s) (where s is a struct and the function does not modify it) because they think they can do a better job than the compiler at figuring out how to pass parameters to functions. I say give control back to the compiler. Lets let "ref" mean "the function may modify the parameter", and the absense of ref mean "the function may not modify the parameter", but leave it to the compiler to decide what is the most efficient way to pass the data to the function.This thought has occurred to me before to. I think issue becomes that the function signature may no longer enough for a compiler to tell what kind of code it needs to generate to call the function.S could be an opaque type so s.sizeof may still be undefined.You can't declare a function that takes an argument of unknown size. You just can't. The compiler will complain that it doesn't know the type. So either your "opaque type" is not allowable, or it's actually a reference/pointer to "opaque type" in which case the size of the pointer *is* known, which is all that is needed, since that's all that will be passed to the function. --bb
Sep 18 2007
Bruce Adams wrote:Bill Baxter Wrote:These opaque types sound suspiciously like D classes/interfaces. void foo(Object o) { assert(o.sizeof == (void*).sizeof); } But C++ polymorphism also allows that, no? But, as other people have pointed out, doing this with structs is a completely different story. -- ReinerBruce Adams wrote:See my reply to Janice on channel B. I did mean its passed by reference. I don't quite get the structs are passed by value by default thing. I'm assuming everything is passed by reference by default but that sometimes you want the compiler to pass by value as for small data types by they classes or structs its more efficient. So my point is that for an opaque type you may not have access to sizeof. An opaque type is like a class or struct whose data members are all private but done properly. You don't need to know about the implementation. C++ forces you to expose the implementation by declaring the members in the header even though they're private and client code can't do anything with them. The caveat is you do still need to know the size to reserve space for an opaque type before its constructed. This is why a C++ compiler needs a full definition. In theory it could be sorted at link time with support from the object file format or even left until run-time. My understanding was that you can do opaque types properly in D though I haven't tried myself. So you have sizeof at link time but not necessarily at compile time. Regards, Bruce.Janice Caron Wrote:You can't declare a function that takes an argument of unknown size. You just can't. The compiler will complain that it doesn't know the type. So either your "opaque type" is not allowable, or it's actually a reference/pointer to "opaque type" in which case the size of the pointer *is* known, which is all that is needed, since that's all that will be passed to the function. --bbOn 9/18/07, Bill Baxter <dnewsgroup billbaxter.com> wrote:S could be an opaque type so s.sizeof may still be undefined.Janice Caron wrote:Actually, I think it's possible my proposal may not have been understood. Under my suggestion, if the caller passes a struct... f(s) ...and the callee declares the function as... void f(S s) ...then all information is known. Both ends must surely know s.sizeof at compile time? And since that's the /only/ thing the compiler needs to know to make the decision.About passing structs by reference: It's one of those things, like register or inline... Once upon a time, programmers used the keyword "register" because they thought they could do a better job than the compiler at figuring how to use its registers. Once upon a time, programmers used the keyword "inline" because they thought they could do a better job than the compiler at figuring out what to inline and what not. Now people explicitly choose between f(s) and f(ref s) (where s is a struct and the function does not modify it) because they think they can do a better job than the compiler at figuring out how to pass parameters to functions. I say give control back to the compiler. Lets let "ref" mean "the function may modify the parameter", and the absense of ref mean "the function may not modify the parameter", but leave it to the compiler to decide what is the most efficient way to pass the data to the function.This thought has occurred to me before to. I think issue becomes that the function signature may no longer enough for a compiler to tell what kind of code it needs to generate to call the function.
Sep 18 2007
On 9/18/07, Bruce Adams <tortoise_74 yeah.who.co.uk> wrote:Could you explain further? I don't understand what an "opaque type" is in D. Observe that the example I cited above explicitly states that s be a struct, not a class. Given that the struct would ordinarily have to be built on the stack at the caller site, and copied onto the stack at the callee site, I just don't see how s.sizeof can be unknown at the time the function is instantiated, /even if/ was declared using a template. What am I missing?Under my suggestion, if the caller passes a struct... f(s) ...and the callee declares the function as... void f(S s) ...then all information is known. Both ends must surely know s.sizeof at compile time? And since that's the /only/ thing the compiler needs to know to make the decision.S could be an opaque type so s.sizeof may still be undefined.
Sep 18 2007
Janice Caron Wrote:On 9/18/07, Bruce Adams <tortoise_74 yeah.who.co.uk> wrote:Right. That was additional information I lost somewhere. That's one thing I've heard bandied around here, that structs are passed by value and classes by reference. It seems too peculiar to be true. Anyway, my comment was based on the understanding that the parameter is passed by reference. A reference is just a pointer. You don't need to know anything about what it points to until you dereference it. E.g. foo(opaque* myvar) { if (this.doIt == true) bar(myvar); } Can be compiled without ever knowing anything about the opaque type. Obviously if its passed by value you know the size because your call pushed it on the stack. Bruce.Could you explain further? I don't understand what an "opaque type" is in D. Observe that the example I cited above explicitly states that s be a struct, not a class. Given that the struct would ordinarily have to be built on the stack at the caller site, and copied onto the stack at the callee site, I just don't see how s.sizeof can be unknown at the time the function is instantiated, /even if/ was declared using a template. What am I missing?Under my suggestion, if the caller passes a struct... f(s) ...and the callee declares the function as... void f(S s) ...then all information is known. Both ends must surely know s.sizeof at compile time? And since that's the /only/ thing the compiler needs to know to make the decision.S could be an opaque type so s.sizeof may still be undefined.
Sep 18 2007
Bruce Adams wrote:That's one thing I've heard bandied around here, that structs are passed by value and classes by reference. It seems too peculiar to be true.It's true. Why do you find this peculiar? Structs are aggregate data structures with value semantics, and classes are aggregate data structures with reference semantics. For some problems you want one, and for some you want the other. Thanks, Nathan Reed
Sep 18 2007
Bill Baxter Wrote: [snip]There would still be a bit of a compiler compatibility issue though. For a given platform Compiler vendors A and B would need to agree on the rules for 'in' parameters or the libs they generate would be incompatible. If we want D to be a language with a unified ABI at least. That suggests that the rules would need to be part of the spec. Heck it may be good enough to just pick a max parameter size and stick with it for all platforms. Just like D picks a size for 'float' and sticks with it for all platforms, whether it's the most efficient for that platform or not. --bbThat's not the same at all. There are internationally approved standards for floating point types. These standards are also implemented in hardware more often that not. Bruce.
Sep 18 2007
Bruce Adams wrote:Bill Baxter Wrote: [snip]Any Walter-approved ABI standards for the D compiler are basically "internationally approved" too. But maybe a better example would have been "just like D picks 64 bits for a long and sticks with it whether it's efficient or not". Whatever. This is really not important. --bbThere would still be a bit of a compiler compatibility issue though. For a given platform Compiler vendors A and B would need to agree on the rules for 'in' parameters or the libs they generate would be incompatible. If we want D to be a language with a unified ABI at least. That suggests that the rules would need to be part of the spec. Heck it may be good enough to just pick a max parameter size and stick with it for all platforms. Just like D picks a size for 'float' and sticks with it for all platforms, whether it's the most efficient for that platform or not. --bbThat's not the same at all. There are internationally approved standards for floating point types. These standards are also implemented in hardware more often that not.
Sep 18 2007
Janice Caron wrote:Lets let "ref" mean "the function may modify the parameter", and the absense of ref mean "the function may not modify the parameter", but leave it to the compiler to decide what is the most efficient way to pass the data to the function. I think this is a neat idea, however it won't work unless the compiler can also do const-checking. This is one more optimisation which having const allows. (And const-by-default would make it obvious).we still need a solution to force pass-by-value and pass-by-reference for exported functions that are called from non-D code.... would no longer compile, because under the new scheme, "ref" is reinterpreted to mean that c is head-const (because C is a class - see definitions in previous post). So instead, you'd have to do: class C; C c; f(&c) void f(ref C* c) { *c = new C(); } Whether or not that would be considered a prohibiting problem, I don't know.if you define ref to mean "be able to change the cell the symbol represents", that isn't needed.
Sep 18 2007
On 9/18/07, Jascha Wetzel <firstname mainia.de> wrote:if you define ref to mean "be able to change the cell the symbol represents", that isn't needed.What I mean was defined in a previous post - hopefully fairly precisely. It was too big a definition to repeat here.
Sep 18 2007
Janice Caron a écrit :About passing structs by reference: It's one of those things, like register or inline... Once upon a time, programmers used the keyword "register" because they thought they could do a better job than the compiler at figuring how to use its registers. Once upon a time, programmers used the keyword "inline" because they thought they could do a better job than the compiler at figuring out what to inline and what not.Well in some (very limited) cases, they still do: I'm thinking about the Linux kernels where developers do care and know (at least in some parts of the kernel) what the compiler do, of course this is not the usual case.. That said, I know that Sun's JVM has some 'escape analysis' optimisation (or it's planned to have this) where it's able to put on the stack some of the objects, but I don't know how efficient it is in comparison to the developer choosing heap or stack allocation.. renoX
Sep 18 2007
renoX Wrote:Janice Caron a écrit :Its not just in the Kernel. It comes up relatively frequently when dealing with large datasets using the STL. If your profile says a small function its taking the most time then inlining it can help. The compiler doesn't know and in general can't know how your code is going to be used, you need the execution profile for that. Bruce.About passing structs by reference: It's one of those things, like register or inline... Once upon a time, programmers used the keyword "register" because they thought they could do a better job than the compiler at figuring how to use its registers. Once upon a time, programmers used the keyword "inline" because they thought they could do a better job than the compiler at figuring out what to inline and what not.Well in some (very limited) cases, they still do: I'm thinking about the Linux kernels where developers do care and know (at least in some parts of the kernel) what the compiler do, of course this is not the usual case..
Sep 18 2007