Good chained function name?

N

Nephi Immortal

I ask you for your opinion what chained function name look like. I do not need to post class definition since you know what I am talking about.

Let’s say for example I have 'A' class.

A a( 1 ), b( 2 ), c( 3 );
int data = a.get_value();
a.set_value( 2 );

What if I am going to write like this below?

a.set_value( b.get_value() + c.get_value() );

They can be to include operator=, operator+, and operator cast. It looksvery readable than getter and setter.

a = b + c;

What if I choose to use chained function name?

a.value() = b.value() + c.value();

Is that readable?

If I name value1() and value2(), I may not want to place them in the main class. I rather prefer to place them in the nested class.

a.Inner().value1() = b.Inner().value1() + c.Inner().value2();

What if I don’t like “Inner()”? It should be removed and operator()() is used.

a().value1() = b().value1() + c().value2();

Do chained function name sound good?

Let’s give some ideas.

int data1, data2, data3;

data1 = a.Get().Bytes();
data2 = b.Get().Kilobytes();
data3 = c.Get().Megabytes();

a.Set().Bytes( 1 );
b.Set().Kilobytes( 2 );
c.Set().Megabytes( 3 );

data1 = a().Bytes();
data2 = b().Kilobytes();
data3 = c().Megabytes();

a().Bytes() = 1;
b().Kilobytes() = 2;
c().Megabytes() = 3;

a().Bytes() = b().Kilobytes() + c().Megabytes();

Please comment if my code looks readable.
 
V

Victor Bazarov

I ask you for your opinion what chained function name look like. I
do
not need to post class definition since you know what I am talking about.
Let’s say for example I have 'A' class.

A a( 1 ), b( 2 ), c( 3 );
int data = a.get_value();
a.set_value( 2 );

What if I am going to write like this below?

a.set_value( b.get_value() + c.get_value() );

They can be to include operator=, operator+, and operator cast. It looks very readable than getter and setter.

a = b + c;

Looks OK to me, as well. Supposedly, the type A is a "value type" that
defines addition as one of its operations.
What if I choose to use chained function name?

Never heard this term, so not sure what the meaning of it is.
a.value() = b.value() + c.value();

Is that readable?

Readability is subjective. To me it's no more readable than a=b+c. Of
course, if each A has different, independently settable values, then it
would make sense to separate them by means of their own accessors.

a.value_blah() = b.value_blah() * c.value_droo();
If I name value1() and value2(), I may not want to place them in the
main class. I rather prefer to place them in the nested class.
a.Inner().value1() = b.Inner().value1() + c.Inner().value2();

I don't see any reason to do so.
What if I don’t like “Inner()� It should be removed and operator()() is used.

a().value1() = b().value1() + c().value2();

Do chained function name sound good?

What's "chained function"?
Let’s give some ideas.

int data1, data2, data3;

data1 = a.Get().Bytes();
data2 = b.Get().Kilobytes();
data3 = c.Get().Megabytes();

a.Set().Bytes( 1 );
b.Set().Kilobytes( 2 );
c.Set().Megabytes( 3 );

data1 = a().Bytes();
data2 = b().Kilobytes();
data3 = c().Megabytes();

a().Bytes() = 1;
b().Kilobytes() = 2;
c().Megabytes() = 3;

a().Bytes() = b().Kilobytes() + c().Megabytes();

Please comment if my code looks readable.

Since the type of 'Bytes', etc., is all the same, it seems to be OK to
add them together. It's not proper from the POV of dimensioned values,
though. In this particular case 'Bytes' and 'Kilobytes' don't look good
as function names, but rather dimensioned types. "Storage", "Volume",
or "Capacity", are better names. Whether the values returned by those
functions are in bytes or kilobytes, can be easily decided, and then you
can easily add those together to yield a value of the more granulated
type, IOW if bytes and kilobytes are added, you get bytes in which
kilobytes are multiplied correspondingly.

So, in short, no, I don't think your code is readable because it does
not reflect anything that would make sense to me. But, again, it can be
all in the eye of the beholder. If you don't intend your code to be
read by anybody else but you, make it readable to *you*, nothing else is
of any importance.

V
 
Ö

Öö Tiib

I ask you for your opinion what chained function name look like.
I do not need to post class definition since you know what I am talking about.


We can imagine how to achieve that.
Let’s say for example I have 'A' class.

A a( 1 ), b( 2 ), c( 3 );

int data = a.get_value();
a.set_value( 2 );

What if I am going to write like this below?

a.set_value( b.get_value() + c.get_value() );

You see yourself that it is too much code bloat. Viewing classes as storage
of values of other types is common but too primitive usage. It
exposes internals and makes error handling hard.
They can be to include operator=, operator+, and operator cast. It
looks very readable than getter and setter.

a = b + c;

Yes, that is done often and is good. Full externally observable "value" of
instance participates (we call it "state"). That state is usually not
representable as single value of some simpler type (like int) that you can
"get".
What if I choose to use chained function name?

a.value() = b.value() + c.value();

If that value is full state, then previous was better. If it is some property
then setter feels wrong, getters look fine:

a.length() = b.length() + c.length(); // worse
a.resize( b.length() + c.length() ); // better
Is that readable?

If I name value1() and value2(), I may not want to place them in the
main class. I rather prefer to place them in the nested class.

a.Inner().value1() = b.Inner().value1() + c.Inner().value2();

Now you expose internals of internals, that endangers your design to grow
into terrible spaghetti.
What if I don’t like “Inner()”? It should be removed and operator()() is
used.

a().value1() = b().value1() + c().value2();

Unreadable. Confusing usage of function call operator. Reserve function
call operator for objects that behave like functions.
Do chained function name sound good?

Let’s give some ideas.

int data1, data2, data3;

data1 = a.Get().Bytes();
data2 = b.Get().Kilobytes();
data3 = c.Get().Megabytes();
a.Set().Bytes( 1 );
b.Set().Kilobytes( 2 );
c.Set().Megabytes( 3 );
data1 = a().Bytes();
data2 = b().Kilobytes();
data3 = c().Megabytes();
a().Bytes() = 1;
b().Kilobytes() = 2;
c().Megabytes() = 3;

I like none. These are names of units of measurement otherwise plural names
feel like container accessors for me.

Use 'discA.size().asKiloBytes()' ... or actually I don't understand your
example. Try to come up with examples closer to practice.
a().Bytes() = b().Kilobytes() + c().Megabytes();

Please comment if my code looks readable.

Adding kilobytes to megabytes and getting bytes? It feels as readable as
any too obvious logic error can be. If I read it I feel that either I don't
understand something major or it is unbelievably wrong. I am confused by
such code.
 
S

Stefan Ram

Öö Tiib said:
a.length() = b.length() + c.length(); // worse
a.resize( b.length() + c.length() ); // better

Should be

a.length( b.length() + c.length() )

according with the standard library:

const int prec = ::std::cout.precision();
::std::cout.precision( prec );
 
V

Victor Bazarov

Should be

a.length( b.length() + c.length() )

according with the standard library:

const int prec = ::std::cout.precision();
::std::cout.precision( prec );

.

The Standard library is but an example of a committee's understanding of
readability. And we know quite well what a horse designed by a
committee looks like. Choosing a noun to also play the role of setting
the value (along with getting it) is not the best approach to concur
readability IMNSHO. Of course to many whose native tongue is not
English it might not matter (no offense is intended). After all, it's
an idiom. The case like this ('blah' without an argument is a getter,
and 'blah' *with an argument* is a setter) might be one case where C++
overloading shines, but I'm reminded that all that glitters is not gold.

V
 
Ö

Öö Tiib

Should be

a.length( b.length() + c.length() )

according with the standard library:

const int prec = ::std::cout.precision();
::std::cout.precision( prec );

Standard library is pile of subtle inconsistencies that can't me edited
because of backward compatibility. The input/output library is notably
different from rest of it AND it is the part that is most frequently
bashed for inefficiency and inconvenience. Less bashed container library
is more consistent with what I wrote:

typedef std::vector<int> Ints;
Ints a( 3, 7 );
Ints b( 5 );
Ints c;

// properties are changed with operations whose name is verb, not noun
c.resize( a.size() + b.capacity() );
c.shrink_to_fit();
// accessors to non-properties are nouns providing references
c.front() = 42;
 
J

Jeff Flinn

I ask you for your opinion what chained function name look like. I do not need to post class definition since you know what I am talking about.

Let’s say for example I have 'A' class.

A a( 1 ), b( 2 ), c( 3 );
int data = a.get_value();
a.set_value( 2 );

What if I am going to write like this below?

a.set_value( b.get_value() + c.get_value() );

They can be to include operator=, operator+, and operator cast. It looks very readable than getter and setter.

a = b + c;

What if I choose to use chained function name?

a.value() = b.value() + c.value();

Is that readable?

Well, the function named 'value' would lead me to believe that it, well
returns by value, and not by reference. So I would expect the above
expression to have no lasting effect as the temporary returned by value
gets it's value set, and then is gone at the ;

Jeff
 
V

Victor Bazarov

Well, the function named 'value' would lead me to believe that it, well
returns by value, and not by reference. So I would expect the above
expression to have no lasting effect as the temporary returned by value
gets it's value set, and then is gone at the ;

So, would you then recommend to have a 'reference' as a function name,
as in

a.reference() = b.value() + c.value();

? 8-[

May I remind you that 'value' *can* mean an L-value just as much as an
R-value? Especially when it appears on the *L*eft side of the
assignment... Just sayin'... ;-)

V
 
J

Jeff Flinn

Well, the function named 'value' would lead me to believe that it, well
returns by value, and not by reference. So I would expect the above
expression to have no lasting effect as the temporary returned by value
gets it's value set, and then is gone at the ;

So, would you then recommend to have a 'reference' as a function name,
as in

a.reference() = b.value() + c.value();

? 8-[

I would avoid the whole approach. I'm assuming the OP's example is just
that: a paired down example. Without a clearer def of the class in
question it's difficult to say what approach should be used, indeed are
these accessor/mutator pairs even needed.

Jeff
 
Ö

Öö Tiib

On 2/13/2013 11:43 PM, Nephi Immortal wrote:
What if I choose to use chained function name?

a.value() = b.value() + c.value();

Is that readable?

Well, the function named 'value' would lead me to believe that it, well
returns by value, and not by reference. So I would expect the above
expression to have no lasting effect as the temporary returned by value
gets it's value set, and then is gone at the ;

So, would you then recommend to have a 'reference' as a function name,
as in

a.reference() = b.value() + c.value();

? 8-[

I would avoid the whole approach. I'm assuming the OP's example is just
that: a paired down example. Without a clearer def of the class in
question it's difficult to say what approach should be used, indeed are
these accessor/mutator pairs even needed.

Try to be more constructive? Your answer feels like Nephi should just
drop dead and stop trying. It is easy to imagine something what can be
under question. Then naming can be discussed. I try to demonstrate:

'value' (as noun) can not be considered non-property of something whose
'value' it is. I never provide properties as L-Values for any by-passer
to store references at and change at will. I feel it error-prone.

I prefer immutable (after construction) properties. I feel it is safer
It can be LOT more efficient if property's value is even set
compile-time. Consider such things about every property.

If there is certain need to mutate a property during object's life-time
then it deserves command-like operations named by verbs. It is better
to make such operations as safe and complete as possible. Keep invariant
of whole object under its own control.

'value' is still hard example since it is fitting verb too. On such cases
I prefer to use some synonymous verb (like 'assess', 'estimate', 'evaluate')
to reduce the possible confusion:

a.revalue( b.price() + c.net_value() );
 
V

Victor Bazarov

[..]
'value' (as noun) can not be considered non-property of something whose
'value' it is. I never provide properties as L-Values for any by-passer
to store references at and change at will. I feel it error-prone.

I prefer immutable (after construction) properties. I feel it is safer
It can be LOT more efficient if property's value is even set
compile-time. Consider such things about every property.

If there is certain need to mutate a property during object's life-time
then it deserves command-like operations named by verbs. It is better
to make such operations as safe and complete as possible. Keep invariant
of whole object under its own control.

'value' is still hard example since it is fitting verb too. On such cases
I prefer to use some synonymous verb (like 'assess', 'estimate', 'evaluate')
to reduce the possible confusion:

a.revalue( b.price() + c.net_value() );

Uh... Perhaps it's a wrong path we're trying to follow. 'Price' is a
verb as well as a noun, 'estimate' is a noun as well as a verb... :)

There is something to be said about 'set' as well (it's a noun too, I am
sure you've heard of 'std::set' :*)), but in combination with another
word it is less likely to be confused. I would definitely prefer
'set_value' to 'revalue' (along with 'value' as a "get"-like accessor).
But that's just me. Keep in mind that readability is still
subjective, let's not try to deceive *ourselves* into thinking that
there can be a complete set of readability rules suitable for everybody.

V
 
L

Luca Risolia

I ask you for your opinion what chained function name look like. I do not need to post class definition since you know what I am talking about.

Let’s say for example I have 'A' class.

A a( 1 ), b( 2 ), c( 3 );
int data = a.get_value();
a.set_value( 2 );

What if I am going to write like this below?

a.set_value( b.get_value() + c.get_value() );

They can be to include operator=, operator+, and operator cast. It looks very readable than getter and setter.

a = b + c;

What if I choose to use chained function name?

a.value() = b.value() + c.value();

Is that readable?

If I name value1() and value2(), I may not want to place them in the main class. I rather prefer to place them in the nested class.

a.Inner().value1() = b.Inner().value1() + c.Inner().value2();

What if I don’t like “Inner()”? It should be removed and operator()() is used.

a().value1() = b().value1() + c().value2();

Do chained function name sound good?

"a = b + c" looks good. All the other alternatives are more difficult to
read.
Let’s give some ideas.

int data1, data2, data3;

data1 = a.Get().Bytes();
data2 = b.Get().Kilobytes();
data3 = c.Get().Megabytes();

a.Set().Bytes( 1 );
b.Set().Kilobytes( 2 );
c.Set().Megabytes( 3 );

data1 = a().Bytes();
data2 = b().Kilobytes();
data3 = c().Megabytes();

a().Bytes() = 1;
b().Kilobytes() = 2;
c().Megabytes() = 3;

a().Bytes() = b().Kilobytes() + c().Megabytes();

Please comment if my code looks readable.

I think it is not readable. It's not type-safe for sure, which makes
your code error-prone. You might loose your spacecraft in the space.

I would suggest a more modern and safe approach, for example:

#include <iostream>

template<int UB, int US>
struct Unit { // a unit in the SI/IEEE systems
enum { B=UB, s=US }; // bytes and seconds
};

template<typename Unit> // a magnitude with a unit
struct Value {
double val; // the magnitude
explicit constexpr Value(double d) : val(d) {} // construct a Value
from a double
// other constructors...
Value operator+(const Value& x) {
return Value(val + x.val);
}
};

using Byte = Unit<1, 0>; // unit: byte
using MemBlock = Value<Byte>; // shortcut

constexpr Value<Byte> operator"" _B(long double d) {
return Value<Byte> (d);
}

constexpr Value<Byte> operator"" _kB(long double d) {
return Value<Byte> (d * 1024);
}

constexpr Value<Byte> operator"" _MB(long double d) {
return Value<Byte> (d * 1024 * 1024);
}

constexpr double to_B(const Value<Byte>& b) { // free functions to be simple
return b.val;
}

constexpr double to_kB(const Value<Byte>& b) {
return b.val / 1024;
}

constexpr double to_MB(const Value<Byte>& b) {
return b.val / 1024 / 1024;
}

// Let's add something useful to the example
using Second = Unit<0, 1>; // unit: sec.
// using Second2 = Unit<0, 2>; // s^2
using Time = Value<Second>; // time in seconds by default
using TransferRate = Value<Unit<1, -1>>; // bytes/second type

constexpr Value<Second> operator"" _s(long double d) {
return Value<Second> (d);
}

constexpr double to_s(const Value<Second>& s) {
return s.val;
}

constexpr TransferRate operator/(const MemBlock& m, const Time& s) {
return TransferRate(to_B(m) / to_s(s));
}

int main() {
MemBlock a = 1024.0_B;
//MemBlock b = 3.0; // NOT OK! unit needed
auto b = 3.0_kB; // OK
auto c = a + b;
std::cout << to_kB(a) << "+" << to_kB(b)
<< " = " << to_kB(c) << '\n'; // or define your operator<<()

// Another example..
TransferRate slow = c / 1.0_s;
auto fast = slow + slow;
// etc..
}
 
N

Nephi Immortal

not need to post class definition since you know what I am talking about.







<shrug> I've seen it done.






Looks OK to me, as well. Supposedly, the type A is a "value type" that

defines addition as one of its operations.






Never heard this term, so not sure what the meaning of it is.

Hi Victor--please see my comments below.
Readability is subjective. To me it's no more readable than a=b+c. Of

course, if each A has different, independently settable values, then it

would make sense to separate them by means of their own accessors.



a.value_blah() = b.value_blah() * c.value_droo();




main class. I rather prefer to place them in the nested class.





I don't see any reason to do so.






What's "chained function"?

See my comment here.

"chained function" mean putting two or more functions together
into one line like this below.

A a;

a().func1().func2(0.func3().etc();

Inner() is nested class. Inner() is in main class to be called and return
Inner class type before chained functions in Inner class can be used.
Inner() can be replaced to operator()().
Since the type of 'Bytes', etc., is all the same, it seems to be OK to

add them together. It's not proper from the POV of dimensioned values,

though. In this particular case 'Bytes' and 'Kilobytes' don't look good

as function names, but rather dimensioned types. "Storage", "Volume",

or "Capacity", are better names. Whether the values returned by those

functions are in bytes or kilobytes, can be easily decided, and then you

can easily add those together to yield a value of the more granulated

type, IOW if bytes and kilobytes are added, you get bytes in which

kilobytes are multiplied correspondingly.

You can create several classes like this below.

class Byte;
class Kilobyte;
class Megabyte;
....
....

Byte, Kilobyte and Megabyte are different types.

What if I show this below?

a().Kilobytes() = b().Bytes + c().Megabytes;

b().Bytes will be converted to Kilobytes by dividing 1024 bytes and
c().Megabytes will be converted to Kilobytes by multiplying 1024 bytes
before the result is to be Kilobyte value.
 
J

Jorgen Grahn

Try to be more constructive? Your answer feels like Nephi should just
drop dead and stop trying.

Ignoring the "drop dead" part, remember that part of the value of
asking questions here is getting "what you're trying to do isn't
useful" type answers. There's room for both kinds.

/Jorgen
 
N

Nephi Immortal

"a = b + c" looks good. All the other alternatives are more difficult to

read.














I think it is not readable. It's not type-safe for sure, which makes

your code error-prone. You might loose your spacecraft in the space.



I would suggest a more modern and safe approach, for example:



#include <iostream>



template<int UB, int US>

struct Unit { // a unit in the SI/IEEE systems

enum { B=UB, s=US }; // bytes and seconds

};



template<typename Unit> // a magnitude with a unit

struct Value {

double val; // the magnitude

explicit constexpr Value(double d) : val(d) {} // construct a Value

from a double

// other constructors...

Value operator+(const Value& x) {

return Value(val + x.val);

}

};



using Byte = Unit<1, 0>; // unit: byte

using MemBlock = Value<Byte>; // shortcut



constexpr Value<Byte> operator"" _B(long double d) {

return Value<Byte> (d);

}



constexpr Value<Byte> operator"" _kB(long double d) {

return Value<Byte> (d * 1024);

}



constexpr Value<Byte> operator"" _MB(long double d) {

return Value<Byte> (d * 1024 * 1024);

}



constexpr double to_B(const Value<Byte>& b) { // free functions to be simple

return b.val;

}



constexpr double to_kB(const Value<Byte>& b) {

return b.val / 1024;

}



constexpr double to_MB(const Value<Byte>& b) {

return b.val / 1024 / 1024;

}



// Let's add something useful to the example

using Second = Unit<0, 1>; // unit: sec.

// using Second2 = Unit<0, 2>; // s^2

using Time = Value<Second>; // time in seconds by default

using TransferRate = Value<Unit<1, -1>>; // bytes/second type



constexpr Value<Second> operator"" _s(long double d) {

return Value<Second> (d);

}



constexpr double to_s(const Value<Second>& s) {

return s.val;

}



constexpr TransferRate operator/(const MemBlock& m, const Time& s) {

return TransferRate(to_B(m) / to_s(s));

}



int main() {

MemBlock a = 1024.0_B;

//MemBlock b = 3.0; // NOT OK! unit needed

auto b = 3.0_kB; // OK

auto c = a + b;

std::cout << to_kB(a) << "+" << to_kB(b)

<< " = " << to_kB(c) << '\n'; // or define your operator<<()



// Another example..

TransferRate slow = c / 1.0_s;

auto fast = slow + slow;

// etc..

}

Your code looks good. Unfortunately, Visual C++ 2012 does not compile!
I looked at MSDN. It says constexpr and other features are not supported.
I think it only supports partial C++x11. Is that true?

If yes, can you please revise your code to remove unsupported features.
 
L

Luca Risolia

Your code looks good. Unfortunately, Visual C++ 2012 does not compile!
I looked at MSDN. It says constexpr and other features are not supported.
I think it only supports partial C++x11. Is that true?

If yes, can you please revise your code to remove unsupported features.

I am sorry, but I don't have VC++2012 at the moment, so I can't answer.
I used GCC 4.7.2:

https://ideone.com/PHh3g5
 
Ö

Öö Tiib

[..]
'value' (as noun) can not be considered non-property of something whose
'value' it is. I never provide properties as L-Values for any by-passer
to store references at and change at will. I feel it error-prone.

I prefer immutable (after construction) properties. I feel it is safer
It can be LOT more efficient if property's value is even set
compile-time. Consider such things about every property.

If there is certain need to mutate a property during object's life-time
then it deserves command-like operations named by verbs. It is better
to make such operations as safe and complete as possible. Keep invariant
of whole object under its own control.

'value' is still hard example since it is fitting verb too. On such cases
I prefer to use some synonymous verb (like 'assess', 'estimate', 'evaluate')
to reduce the possible confusion:

a.revalue( b.price() + c.net_value() );

Uh... Perhaps it's a wrong path we're trying to follow. 'Price' is a
verb as well as a noun, 'estimate' is a noun as well as a verb... :)

It is difficult only because of so lot of verbs and nouns are homonyms
in English. In Russian for example where commanding verb rarely is
homonym for some noun it would not be problem at all. It is not
wrong in English ... just more difficult.
There is something to be said about 'set' as well (it's a noun too, I am
sure you've heard of 'std::set' :*)), but in combination with another
word it is less likely to be confused. I would definitely prefer
'set_value' to 'revalue' (along with 'value' as a "get"-like accessor).
But that's just me. Keep in mind that readability is still
subjective, let's not try to deceive *ourselves* into thinking that
there can be a complete set of readability rules suitable for everybody.

When I see some code that is easy to read then it is usually master
involved. So it is art. What rules can achieve is uniform quality that
is usually readable enough. Worst is inconsistent mix of unfitting and
contradicting concepts. Your usage of set prefix is great for me if it
is used consistently for same thing all over the code-base.
 
Ö

Öö Tiib

Ignoring the "drop dead" part, remember that part of the value of
asking questions here is getting "what you're trying to do isn't
useful" type answers. There's room for both kinds.

There is. Trying to make some rules how to name classes, variables
and functions in your code feels like good idea. So I disagreed that
it does deserve such answer. I trust that it is worth trying. There
maybe can not be universal naming approach that fits for every
problem domain but everybody end up using something. It makes
life easier.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,020
Latest member
GenesisGai

Latest Threads

Top