Re: [boost] Re: class proposal
Justin M. Lewis wrote: I agree. I probably wouldn't have cared for this myself, had I never seen the code I'm working on now. I mean, normally I work pretty independently. But, now I'm stuck with the job of maintaining code that's been around forever, has been ported several times to a couple different projects. In places you can see how the code evolved over time. But, the point is, it's becoming a mess. And, we're at a point where we're almost starting everything again, but this time from scratch. Knowing that the code will probably live for years, and be ported several times, and be maintained by many different people over its life, it seems best to me to start a project like that off with clarity being the #1 priority. And, at least in my experience, people seem to think that functions that pass by reference changing the values of params is a problem, it's hard to track. But, most C++ people I know prefer to avoid pointer use. So, that really only leaves the one option that makes the intent explicit and clear, every time. So, I really can't give a long term analysis of how well this method works, if it becomes a hassle to maintain it, or not. But, as it is, it seems more clear to me than anything else. At the cost of 3 or 6 letters at the invocation point, you can make the operation of the function clear. func(out(x)); It seems pretty simple and straight forward to me. I believe all that will be accomplished is that these objects will become ubiquitous in the system just as references are. For example, code like the following will start to pop up: void f( in_out int is_not_changed_ ) { // use is_not_changed_, but don't change it } IMHO, why not just state from the start to ban in/out parameters? In its place, use parameters for in and return for out. An in/out can done via a smart pointer. Noel ___ Unsubscribe other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Re: [boost] Re: class proposal
void f( in_out int is_not_changed_ ) { // use is_not_changed_, but don't change it } I think there would be a much bigger problem (code inside the function would change). Just consider void add_char( std::string str, char ch) { str += ch; } Now, if we change it so be in_out, we'll have to use a .ref()-like function. void add_char( in_outstd::string str, char ch) { str.ref() += ch; } Of course, this is a simple example, but it illustrates the point. The code would become obfuscated. Frankly, I donot like it. Best, John ___ Unsubscribe other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Re: [boost] Re: class proposal
- Original Message - From: Noel Yap [EMAIL PROTECTED] To: Boost mailing list [EMAIL PROTECTED] Sent: Thursday, April 24, 2003 4:13 AM Subject: Re: [boost] Re: class proposal Justin M. Lewis wrote: in/out seems to be used fairly commonly in COM. I'm not sure I have any great examples off the top of my head, but I know they're commonly used. I'm not a COM person, but I believe it's written in C. If so, then you are correct that in/out parameters are more needed since noone would want to create a struct for each multiple return type. OTOH, C++ has templates to deal with this situation (ie boost::tuple) so, qualifying my previous statement, in C++ I still see no need for in/out parameters. I think most COM objects are written in C++. I should have been more specific here, if you're looking at ActiveX objects, in/out params are used all over the place. Each function returns an HRESULT, iirc, any data you want returned has to be returned in a param. And using pointers is part of what we're trying to avoid here. Like I said, I avoid using pointers whenever possible at this point. I'm a little confused. Either you pass in the entire object or you pass in a pointer (even if it's wrapped in another class). How is this new class supposed to be implemented? And, it's not either pass in a whole object or pass in a pointer, you're forgetting references. This new class takes in a reference, and stores that. It doesn't do anything with pointers. And, again, the real intent here is to insure clarity at the point of invocation. In my case I'm looking at 100's of thousands of lines of code, written over the past 8 years. It's tiresome trying to chase down where values COULD have changed. In this setup you KNOW exactly what calls are changing parameter values, and it's enforced. As long as the library calls use the c_out and c_in_out classes people using the library are forced to conform to the format. So, 8 years, and a few million lines of code later, no one will wonder what might cause a variable they're tracking to change values. I think if parameters are used for in parameters only and return values are used for out parameters only, the same thing is achieved. For example, inOutValue = square( inOutValue ); vs (using an extension for generality): square( c_in_out typeof( inOutValue ) ( inOutValue ) ); Noel And, again, returning an object isn't always desirable, you could be copying large objects for no reason. You may not call a copy constructor, but an = operator is being used. ___ Unsubscribe other changes: http://lists.boost.org/mailman/listinfo.cgi/boost ___ Unsubscribe other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Re: [boost] Re: class proposal
I diagree with this. The code I've written using this looks more like void add_char( in_outstd::string str, char ch) { std::string s = str; s += ch; } - Original Message - From: John Torjo [EMAIL PROTECTED] To: Boost mailing list [EMAIL PROTECTED] Sent: Thursday, April 24, 2003 5:20 AM Subject: Re: [boost] Re: class proposal void f( in_out int is_not_changed_ ) { // use is_not_changed_, but don't change it } I think there would be a much bigger problem (code inside the function would change). Just consider void add_char( std::string str, char ch) { str += ch; } Now, if we change it so be in_out, we'll have to use a .ref()-like function. void add_char( in_outstd::string str, char ch) { str.ref() += ch; } Of course, this is a simple example, but it illustrates the point. The code would become obfuscated. Frankly, I donot like it. Best, John ___ Unsubscribe other changes: http://lists.boost.org/mailman/listinfo.cgi/boost ___ Unsubscribe other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Re: [boost] Re: class proposal
Justin M. Lewis wrote: And, it's not either pass in a whole object or pass in a pointer, you're forgetting references. This new class takes in a reference, and stores that. It doesn't do anything with pointers. I didn't really forget references. IMHO, references are pointers that are implicitly dereferenced. At the machine level, they are typically treated the same (eg address is passed by value). And, again, returning an object isn't always desirable, you could be copying large objects for no reason. You may not call a copy constructor, but an = operator is being used. My reply to this was to use smart pointers. But as Terje Slettebø pointed out (but I got distracted by work before sending out my reply), smart pointers don't resolve the problem that the object may still change from underneath. I still think there's no need for the proposed wrapper class since: void f( T value_may_change_, T const value_may_not_change_ ); is still an acceptible alternative. IOW, if users stick to using T only to indicate values that may change, and T const to indicate values that may not change, the wrapper class has no added value (forgive the unintended pun). Noel -- NOTICE: If received in error, please destroy and notify sender. Sender does not waive confidentiality or privilege, and use is prohibited. ___ Unsubscribe other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Re: [boost] Re: class proposal
Justin M. Lewis wrote: I diagree with this. The code I've written using this looks more like void add_char( in_outstd::string str, char ch) { std::string s = str; s += ch; } I think you're assuming everyone will code the way you want. If you're going to force everyone to code this way, why not just have them code like: void add_char( std::string str_, char ch_ ) { str += ch; } int len( std::string const str ) { return str.length(); } What is the added value of the proposed class? It's not that it forces people to change the value if it's used: int len( in_out std::string str ) { return static_cast std::string ( str ).length(); } Noel -- NOTICE: If received in error, please destroy and notify sender. Sender does not waive confidentiality or privilege, and use is prohibited. ___ Unsubscribe other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Re: [boost] Re: class proposal
Everyone is ignoring the possibility of objects that can't be copied in this, too. Some objects intentionally hide their operator =, making returning it from a function impossible. And, I think a lot of people are missing a big part of the point here. You can enforce the use of making it explicit at the point of invocation that the param is changing. The compiler will give an error if a c_out or c_in_out object isn't passed. You can't enforce a naming convention or commenting at the point of invocation, at least not everywhere, like where I work. So, by writing a function using these objects, it's a guarantee that anyone who uses my functions has to make it explicit what the effect of calling my functions is. - Original Message - From: Noel Yap [EMAIL PROTECTED] To: Boost mailing list [EMAIL PROTECTED] Sent: Thursday, April 24, 2003 4:13 AM Subject: Re: [boost] Re: class proposal Justin M. Lewis wrote: in/out seems to be used fairly commonly in COM. I'm not sure I have any great examples off the top of my head, but I know they're commonly used. I'm not a COM person, but I believe it's written in C. If so, then you are correct that in/out parameters are more needed since noone would want to create a struct for each multiple return type. OTOH, C++ has templates to deal with this situation (ie boost::tuple) so, qualifying my previous statement, in C++ I still see no need for in/out parameters. And using pointers is part of what we're trying to avoid here. Like I said, I avoid using pointers whenever possible at this point. I'm a little confused. Either you pass in the entire object or you pass in a pointer (even if it's wrapped in another class). How is this new class supposed to be implemented? And, again, the real intent here is to insure clarity at the point of invocation. In my case I'm looking at 100's of thousands of lines of code, written over the past 8 years. It's tiresome trying to chase down where values COULD have changed. In this setup you KNOW exactly what calls are changing parameter values, and it's enforced. As long as the library calls use the c_out and c_in_out classes people using the library are forced to conform to the format. So, 8 years, and a few million lines of code later, no one will wonder what might cause a variable they're tracking to change values. I think if parameters are used for in parameters only and return values are used for out parameters only, the same thing is achieved. For example, inOutValue = square( inOutValue ); vs (using an extension for generality): square( c_in_out typeof( inOutValue ) ( inOutValue ) ); Noel ___ Unsubscribe other changes: http://lists.boost.org/mailman/listinfo.cgi/boost ___ Unsubscribe other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
RE: [boost] Re: class proposal
That depends. At one point the out and in_out classes had assert checks in them. c_out would check to make sure that it was assigned some value inside the called function, for example. The other thing is, the idea here is to force people CALLING your function (func) to show the world what's going on by using the out or in_out function at the point func is called. You'd also want totally separate types that can't be implicitly cast from one to the other, since the point here is to make it clear at the point func is called what is happening to the parameters that are passed. -Original Message- From: [EMAIL PROTECTED] [mailto:[EMAIL PROTECTED] On Behalf Of Gennadiy Rozental Sent: Wednesday, April 23, 2003 1:20 AM To: [EMAIL PROTECTED] Subject: [boost] Re: class proposal void func(CRetValint x){x = 1977;}; Basically boost::ref could be used for the same purpose, isn't it? Just different name Gennadiy. ___ Unsubscribe other changes: http://lists.boost.org/mailman/listinfo.cgi/boost ___ Unsubscribe other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Re: [boost] Re: class proposal
From: Justin M. Lewis [EMAIL PROTECTED] Well, I guess, based on all the code I've been reading at work it didn't seem so small, chasing down all kinds of functions across 100's of files to see why exactly values are changing mid function I'm looking at without warning. Anyway, this would allow for stronger enforcement of the rule that changing params should be marked somehow. As the programmer of a library people are using, I can force them to mark the params they're passing as out or in_out, so in 5 years when someone else comes along and has to debug it, it's all clear what's happening. Why not use T if the function may change it, and const T if it won't? Simple and clear. No need to use pointers, to differentiate between it. An advantage with references is that you may pass by value, or const reference, and to the caller, it's called in the same way, so the pass by value or const reference may be an implementation detail. Regards, Terje ___ Unsubscribe other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
RE: [boost] Re: class proposal
Sorry if the explanation is a bit confusing. The whole idea here is to make it explicit at the function invocation that a parameter being passed will be used to return a value. A good example of where this would be useful is with a function call that takes some params, and returns several different things in different params, and still has an explicit return for an error code. At the invocation point it would be impossible to tell what's going on. int chk; chk = GetSomething(p1, p2, p3, p4, p5); where the actual declaration of GetSomething is like int GetSomething(int ret1, int ret2, int v1, int v2, int v3); It's impossible to tell at the invocation which params are returning, and which are being used to calculate the return. At the invocation it looks like chk might be what you're trying to get. With classes like I'm suggesting it would be obvious, the declaration would be: int GetSomething(c_outint ret1, c_outint ret2, int v1, int v2, int v3); And at the invocation now, it has to be explicit that those first 2 params are out params. chk = GetSomething(out(p1), out(p2), p3, p4, p5); It REQUIRES you to use the out helper function at the invocation, so anyone reading the code later can see, without checking the implementation of GetSomething, that those 2 params are being set, and the last ones are not. -Original Message- From: [EMAIL PROTECTED] [mailto:[EMAIL PROTECTED] On Behalf Of Terje Slettebø Sent: Wednesday, April 23, 2003 11:17 AM To: Boost mailing list Subject: Re: [boost] Re: class proposal From: Terje Slettebø [EMAIL PROTECTED] From: Justin M. Lewis [EMAIL PROTECTED] Well, I guess, based on all the code I've been reading at work it didn't seem so small, chasing down all kinds of functions across 100's of files to see why exactly values are changing mid function I'm looking at without warning. Anyway, this would allow for stronger enforcement of the rule that changing params should be marked somehow. As the programmer of a library people are using, I can force them to mark the params they're passing as out or in_out, so in 5 years when someone else comes along and has to debug it, it's all clear what's happening. Why not use T if the function may change it, and const T if it won't? After I sent it, I realised that the issue was marking it at the _caller's_ side, so then this doesn't apply. It was a little difficult to understand the proposal, as it mentioned c_in_out and c_out, while the code example uses CRetVal and the retval function. Regards, Terje ___ Unsubscribe other changes: http://lists.boost.org/mailman/listinfo.cgi/boost ___ Unsubscribe other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Re: [boost] Re: class proposal
Yes, it is better. The first example has the problem of, you still have to go look up the function to see if it's actually changing anything, or if it's taking the param in, reading teh value, then modifying based on what was read. The second example has the problem of copying a potentially large object, and it doesn't allow for in/out params. - Original Message - From: Gregory Colvin [EMAIL PROTECTED] To: Boost mailing list [EMAIL PROTECTED] Sent: Wednesday, April 23, 2003 5:34 PM Subject: Re: [boost] Re: class proposal On Wednesday, Apr 23, 2003, at 16:07 America/Denver, Justin M. Lewis wrote: Sorry if the explanation is a bit confusing. The whole idea here is to make it explicit at the function invocation that a parameter being passed will be used to return a value. A good example of where this would be useful is with a function call that takes some params, and returns several different things in different params, and still has an explicit return for an error code. At the invocation point it would be impossible to tell what's going on. int chk; chk = GetSomething(p1, p2, p3, p4, p5); where the actual declaration of GetSomething is like int GetSomething(int ret1, int ret2, int v1, int v2, int v3); It's impossible to tell at the invocation which params are returning, and which are being used to calculate the return. At the invocation it looks like chk might be what you're trying to get. With classes like I'm suggesting it would be obvious, the declaration would be: int GetSomething(c_outint ret1, c_outint ret2, int v1, int v2, int v3); And at the invocation now, it has to be explicit that those first 2 params are out params. chk = GetSomething(out(p1), out(p2), p3, p4, p5); It REQUIRES you to use the out helper function at the invocation, so anyone reading the code later can see, without checking the implementation of GetSomething, that those 2 params are being set, and the last ones are not. Is this really that much better than chk = GetSomething(p1, p2, p3, p4, p5); or GotSomething ret = GetSomething(p3,p4,p5); ? ___ Unsubscribe other changes: http://lists.boost.org/mailman/listinfo.cgi/boost ___ Unsubscribe other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Re: [boost] Re: class proposal
Justin M. Lewis wrote: Yes, it is better. The first example has the problem of, you still have to go look up the function to see if it's actually changing anything, or if it's taking the param in, reading teh value, then modifying based on what was read. Then how about: boost::tuple boost::shared_ptr LargeObject result = f( largeObjectSharedPtr ); The second example has the problem of copying a potentially large object, and it doesn't allow for in/out params. I'm still not convinced that in/out parameters are necessary. Noel -- NOTICE: If received in error, please destroy and notify sender. Sender does not waive confidentiality or privilege, and use is prohibited. ___ Unsubscribe other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Re: [boost] Re: class proposal
I agree. I probably wouldn't have cared for this myself, had I never seen the code I'm working on now. I mean, normally I work pretty independently. But, now I'm stuck with the job of maintaining code that's been around forever, has been ported several times to a couple different projects. In places you can see how the code evolved over time. But, the point is, it's becoming a mess. And, we're at a point where we're almost starting everything again, but this time from scratch. Knowing that the code will probably live for years, and be ported several times, and be maintained by many different people over its life, it seems best to me to start a project like that off with clarity being the #1 priority. And, at least in my experience, people seem to think that functions that pass by reference changing the values of params is a problem, it's hard to track. But, most C++ people I know prefer to avoid pointer use. So, that really only leaves the one option that makes the intent explicit and clear, every time. So, I really can't give a long term analysis of how well this method works, if it becomes a hassle to maintain it, or not. But, as it is, it seems more clear to me than anything else. At the cost of 3 or 6 letters at the invocation point, you can make the operation of the function clear. func(out(x)); It seems pretty simple and straight forward to me. Justin - Original Message - From: Alisdair Meredith [EMAIL PROTECTED] To: [EMAIL PROTECTED] Sent: Wednesday, April 23, 2003 7:01 PM Subject: [boost] Re: class proposal Justin M. Lewis wrote: My idea was, if you make a simple template class, originally I called it CRetVal, you could force people to specify at the time the function is called what's going on. I made a helper template function retval that would create and return a CRetVal object of the desired type to save from needing to use template notation in line all over the place. So, the above would become something more like. void func(CRetValint x){x = 1977;}; Interesting idea. I think I like it, similar to the way I like the idea of an unmanaged_ptr template to indicate deliberate raw pointer use clearly. Unfortunately, I think it is a hard sell, persuading people to type many more characters to do something they have been familiar with using much leaner syntax for years. If clarity matters it is usually indicated by clear function/parameter naming, handily placed comments etc. so various strategies for coping with the problem are out there. Persuading people that the increased clarity of intent for the single parameter is worth the extra code-obfuscation of the call as a whole (as any additional wrapper-syntax tends to obfuscate) may be a hard sell. On the basis that nothing teaches like experience I'd certainly be interested in giving it a go here though g -- AlisdairM ___ Unsubscribe other changes: http://lists.boost.org/mailman/listinfo.cgi/boost ___ Unsubscribe other changes: http://lists.boost.org/mailman/listinfo.cgi/boost