Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Need help implementing command line args on Apple-world & other systems

72 views
Skip to first unread message

Alf P. Steinbach

unread,
Jul 7, 2017, 7:09:15 AM7/7/17
to
It so happens that I don't have any Apple equipment, and since I'm
rather poor I can't afford to just buy it.

I've just implemented the following declaration for Windows and Linux:

<url:
https://github.com/alf-p-steinbach/stdlib/blob/master/source/extension/process_command_line.declarations.hpp>


inline auto command_line() -> string;

class Command_line_args
{
private:
vector<string> items_;

public:
auto begin() const { return items_.begin(); }
auto end() const { return items_.end(); }

auto size() const -> Size { return items_.size(); }

auto operator[]( Index const i ) const
-> ref_<const string>
{ return items_.at( i ); }

inline Command_line_args();
};


Here's the Linux implementation (it appears to work, in Ubuntu in a
Virtual Box):

<url:
https://github.com/alf-p-steinbach/stdlib/blob/master/source/_impl/linux_process_command_line.hpp>


namespace impl {
inline auto get_command_line_data()
-> string
{
const string path = "/proc/" + to_string( getpid() ) +
"/cmdline";
ifstream f{ path };
hopefully( not f.fail() )
or fail( "stdlib::impl::get_command_line_data - failed
to open “" + path + "”" );
string result;
getline( f, result )
or fail( "stdlib::impl::get_command_line_data - failed
to read “" + path + "”" );
return result;
}
} // namespace impl

inline auto process::command_line()
-> string
{
// TODO: needs quoting of parts as necessary.
string result = impl::get_command_line_data();
replace( result.begin(), result.end(), '\0', ' ' );
return result;
};

inline process::Command_line_args::Command_line_args()
{
const string s = impl::get_command_line_data();
int i = 0;
for( char const* p = &s[0]; *p; p += strlen( p ) + 1 )
{
items_.push_back( p );
}
}


In addition to never having done anything on the Mac except helping a
person type a character that wasn't directly available on the keyboard,
I've never cooperated with anyone on GitHub. I guess it's just a matter
of the other person have a username there so can be added as maintainer
on the project? If you can help to write corresponding code for some
other system than Windows and Linux that would be great!

And I'm not really very familiar with Linux either, so, for example, I
have no ready knowledge about how to quote the command line – the TODO:
comment in the code above – so that it can be parsed back into its
constituent argument parts? Or is that not possible perhaps?


Cheers!,

- Alf

Ralf Goertz

unread,
Jul 7, 2017, 8:25:36 AM7/7/17
to
Am Fri, 7 Jul 2017 13:08:52 +0200
schrieb "Alf P. Steinbach" <alf.p.stein...@gmail.com>:

> And I'm not really very familiar with Linux either, so, for example, I
> have no ready knowledge about how to quote the command line – the
> TODO: comment in the code above – so that it can be parsed back into
> its constituent argument parts? Or is that not possible perhaps?

There is no need for this line:

replace( result.begin(), result.end(), '\0', ' ' );

under Linux, since the cmdline file in proc already separates the
arguments by '\0'. Furthermore, you can change this line:

const string path = "/proc/" + to_string( getpid() ) + "/cmdline";

to this:

const string path = "/proc/self/cmdline";

since in proc you get a link to your own pid named "self".

HTH Ralf

Mr Flibble

unread,
Jul 7, 2017, 9:26:38 AM7/7/17
to
On 07/07/2017 12:08, Alf P. Steinbach wrote:
> It so happens that I don't have any Apple equipment, and since I'm
> rather poor I can't afford to just buy it.
>
> I've just implemented the following declaration for Windows and Linux:
>
> <url:
> https://github.com/alf-p-steinbach/stdlib/blob/master/source/extension/process_command_line.declarations.hpp>
>
>
>
> inline auto command_line() -> string;
>
> class Command_line_args
> {
> private:
> vector<string> items_;
>
> public:
> auto begin() const { return items_.begin(); }
> auto end() const { return items_.end(); }
>
> auto size() const -> Size { return items_.size(); }
>
> auto operator[]( Index const i ) const
> -> ref_<const string>
> { return items_.at( i ); }
>
> inline Command_line_args();
> };

1) Member data should come after member functions.
2) Private should come after public.
3) Your use of auto in a class interface is inappropriate; auto use at
client site is fine but at API level it just obfuscates: what is the
fucking return type?
4) Your mixture of capital letter and underscores for class names is
egregious.
5) std::vector::at() can throw whilst std::vector::operator[] doesn't so
it is confusing to mix the two as you are doing.
6) Your use of inline keyword for in-class function declaration seems bogus.

/Flibble

Gareth Owen

unread,
Jul 7, 2017, 11:31:44 AM7/7/17
to
Mr Flibble <flibbleREM...@i42.co.uk> writes:

> 1) Member data should come after member functions.

Beside "convention", is there any reason for this rule?

My tendency is to group public data and public functions together, so
the user can see the whole API/contract/"interface" in one place.

> 2) Private should come after public.

This one makes sense.

<Eminently sensible stuff snipped>

Alf P. Steinbach

unread,
Jul 7, 2017, 11:47:06 AM7/7/17
to
On 07-Jul-17 2:25 PM, Ralf Goertz wrote:
> Am Fri, 7 Jul 2017 13:08:52 +0200
> schrieb "Alf P. Steinbach" <alf.p.stein...@gmail.com>:
>
>> And I'm not really very familiar with Linux either, so, for example, I
>> have no ready knowledge about how to quote the command line – the
>> TODO: comment in the code above – so that it can be parsed back into
>> its constituent argument parts? Or is that not possible perhaps?
>
> There is no need for this line:
>
> replace( result.begin(), result.end(), '\0', ' ' );
>
> under Linux, since the cmdline file in proc already separates the
> arguments by '\0'.

<url: http://en.cppreference.com/w/cpp/algorithm/replace>

It replaces every `'\0'` with a space, to synthesize a possible original
command line like the one in Windows. The idea is to provide
conceptually the same on all platforms. Hence the need for quoting for
the general case, if I understand this correctly (I'm not 100% sure).


> Furthermore, you can change this line:
>
> const string path = "/proc/" + to_string( getpid() ) + "/cmdline";
>
> to this:
>
> const string path = "/proc/self/cmdline";
>
> since in proc you get a link to your own pid named "self".

Thanks! :)


Cheers!,

- Alf

Alf P. Steinbach

unread,
Jul 7, 2017, 12:13:30 PM7/7/17
to
On 07-Jul-17 3:26 PM, Mr Flibble wrote:
> On 07/07/2017 12:08, Alf P. Steinbach wrote:
>> It so happens that I don't have any Apple equipment, and since I'm
>> rather poor I can't afford to just buy it.
>>
>> I've just implemented the following declaration for Windows and Linux:
>>
>> <url:
>> https://github.com/alf-p-steinbach/stdlib/blob/master/source/extension/process_command_line.declarations.hpp>
>>
>>
>>
>> inline auto command_line() -> string;
>>
>> class Command_line_args
>> {
>> private:
>> vector<string> items_;
>>
>> public:
>> auto begin() const { return items_.begin(); }
>> auto end() const { return items_.end(); }
>>
>> auto size() const -> Size { return items_.size(); }
>>
>> auto operator[]( Index const i ) const
>> -> ref_<const string>
>> { return items_.at( i ); }
>>
>> inline Command_line_args();
>> };
>
> 1) Member data should come after member functions.
> 2) Private should come after public.

I have a different and, I believe, just as well-informed opinion.


> 3) Your use of auto in a class interface is inappropriate; auto use at
> client site is fine but at API level it just obfuscates: what is the
> fucking return type?

You could write out the return type as `vector<string>::const_iterator`,
but that's just brittle and without value. I think the case above must
surely have been one of the motivating cases for C++14 deduced return
type. We don't care about the actual concrete iterator type: it can be
whatever it is, and best if it automatically follows the container type
and possible changes of constness of the member function and so on.


> 4) Your mixture of capital letter and underscores for class names is
> egregious.

I capitalize type names.

E.g. in some cases it's convenient to have a variable and a type of the
same name, just with different capitalization, and also, in some cases
it's convenient to have a type with the same name as a core language or
standard library type, except for capitalization. So I've found it to be
a nice convention. I've used many different conventions over the years.


> 5) std::vector::at() can throw whilst std::vector::operator[] doesn't so
> it is confusing to mix the two as you are doing.

As I see it, the need for superfast indexing of command line arguments
is non-existent.

Then convenient range-checking can be provided at no cost, so it is. :)

Since it's part of the interface (contract) of this class, it's in the
interface, and it's hereby proved that that contract is noticed, thanks.


> 6) Your use of inline keyword for in-class function declaration seems
> bogus.

It tells you (very clearly) that the definition of that function is
and/or should be provided textually inline in header code.

And it tells you that, not as a hint that you'd have to figure out, but
as absolutely required by the language rules,

except, to be pedantic, that the standard allows code to be provided by
a database or magic or whatever, not necessarily as files.

The `inline` keyword has to be either on the in-class declaration, or on
the definition, or both.

Choosing to place it only on the definition would communicate the least,
the minimum, to a reader of the code, opposite of what I want.


Cheers!,

- Alf

Manfred

unread,
Jul 7, 2017, 2:39:01 PM7/7/17
to
On 7/7/2017 5:46 PM, Alf P. Steinbach wrote:
> It replaces every `'\0'` with a space, to synthesize a possible original
> command line like the one in Windows. The idea is to provide
> conceptually the same on all platforms. Hence the need for quoting for
> the general case, if I understand this correctly (I'm not 100% sure).

I, for one, find the *nix cmdline arg handling definitely better
designed than Windows's (which in fact does nothing useful with it), so
why the attempt to build a Windows-like command line, and not the other
way around?
If you wish, your library could set up a decent argc/argv set from the
Windows command line, e.g. including wildchar expansion and the like.
A lot could be done in that direction (ref the sh/bash manpage) although
I cannot say if it can be worth the effort at all on Windows, given the
limited use of cmdline args on this platform.
On the other hand, a program targeted for *nix most probably wants to
use the native argc/argv, since they are quite effectively preprocessed
by the shell, and it wants to make use of its features.

I am not sure what you mean about need for quoting, anyway on *nix
quoting is processed by the shell, and it is removed after interpreting
that a quoted string has to be parsed in its well defined way (e.g. as a
single argument if it includes spaces - the QUOTING subsection of the
bash manpage is two pages of dense specification) before passing the
result to the program.

Alf P. Steinbach

unread,
Jul 7, 2017, 3:33:57 PM7/7/17
to
On 07-Jul-17 8:38 PM, Manfred wrote:
> On 7/7/2017 5:46 PM, Alf P. Steinbach wrote:
>> It replaces every `'\0'` with a space, to synthesize a possible
>> original command line like the one in Windows. The idea is to provide
>> conceptually the same on all platforms. Hence the need for quoting for
>> the general case, if I understand this correctly (I'm not 100% sure).
>
> I, for one, find the *nix cmdline arg handling definitely better
> designed than Windows's (which in fact does nothing useful with it), so
> why the attempt to build a Windows-like command line, and not the other
> way around?

I provide both. See the interface presented in original posting. I like
the Winnie the Pooh response to “honey or syrup?”, namely “both, thank
you”. :)


> If you wish, your library could set up a decent argc/argv set from the
> Windows command line,

It does.


> e.g. including wildchar expansion and the like.

Yes, I've considered that, thanks!, but, first of all, I must do one
thing at a time. And secondly, as opposed to providing command line
arguments in UTF-8, which is both an implementation fix and a core
language + standard library design level fix, I think wildchar expansion
would be a distinct /extension/ of the C++ standard library. In
contrast, the intent of /stdlib/ is just to fix the implementation, to
provide a more practically usable implementation. Wrt. that goal of
limitation providing command line arguments is border-line already, and
necessarily treated as an extension, but I think it may be crucial to
enable and foster adoption of the library. For only if /stdlib/ makes
client code at least as convenient or more convenient than with the
/NoWide/ library (adopted in Boost last month), will it fly, I think.

But doing that by default, as MinGW g++ unfortunately does for the
arguments of `main`, breaks expectation in Windows: it does not conform
to the convention established by the main compiler for the platform.

For example, the Windows / Visual C++ approach allows you to write a
`fastmove` program that accepts `fastmove *.bah someplace\*.foo`. That
will just not work with with MinGW g++'s default. And I don't know any
way to tell MinGW g++ to not do that. :(

The current design of fetching the data from the OS on all systems, is
in part motivated by the need to fix MinGW g++'s effectively broken
implementation: since I fail to fix it, I provide an alternative.

And partly this design is motivated by MinGW g++ not conforming to the
Visual C++ convention wrt. to the `__argv` and `__argc` variables (it's
a Windows thing). Changing these works with Visual C++, but doesn't
affect the arguments that MinGW g++ passes to `main`. Thus it's
apparently not possible with a transparent fix of MinGW g++'s behavior,
and the /NoWide/ solution of passing on argc and argv, is abhorrent to
me (I also suspect that it's simply wrong when pitted against MinGW g++
and wildcard arguments, but I haven't tested that yet).


> A lot could be done in that direction (ref the sh/bash manpage) although
> I cannot say if it can be worth the effort at all on Windows, given the
> limited use of cmdline args on this platform.

Command line args are used most every time you “open” a file in Windows,
e.g. by double-clicking it.


> On the other hand, a program targeted for *nix most probably wants to
> use the native argc/argv, since they are quite effectively preprocessed
> by the shell, and it wants to make use of its features.

Yes.

Except where one makes use of some 3rd party top level code, where one
doesn't have access to the `main` arguments.


> I am not sure what you mean about need for quoting, anyway on *nix
> quoting is processed by the shell, and it is removed after interpreting
> that a quoted string has to be parsed in its well defined way (e.g. as a
> single argument if it includes spaces - the QUOTING subsection of the
> bash manpage is two pages of dense specification) before passing the
> result to the program.

Well I meant the `command_line()` function to produce a possible command
line that, when used to create a new process, would reproduce exactly
the command line args here.

Client code that needs the individual arguments can just access them via
`Command_line_args`.


Cheers!, & thanks for your feedback,

- Alf

Daniel

unread,
Jul 7, 2017, 3:39:08 PM7/7/17
to
On Friday, July 7, 2017 at 9:26:38 AM UTC-4, Mr Flibble wrote:
> On 07/07/2017 12:08, Alf P. Steinbach wrote:

> > class Command_line_args
> > {
> > private:
> > vector<string> items_;
> >
> > public:
> > auto begin() const { return items_.begin(); }
> > auto end() const { return items_.end(); }
> >
> > auto size() const -> Size { return items_.size(); }
> >
> > auto operator[]( Index const i ) const
> > -> ref_<const string>
> > { return items_.at( i ); }
> >
> > inline Command_line_args();
> > };
>
> 1) Member data should come after member functions.

Disagree, implementors need to see the member data, and it's handy to
have it at the top.

> 2) Private should come after public.

Disagree, at least for member data.

> 3) Your use of auto in a class interface is inappropriate; auto use at
> client site is fine but at API level it just obfuscates: what is the
> fucking return type?

Agree :-)

> 4) Your mixture of capital letter and underscores for class names is
> egregious.

Agree. Stroustrup once recommended this style, but I've never seen it used, and Stroustrup's latest style guide proposes PascalCase.

> 5) std::vector::at() can throw whilst std::vector::operator[] doesn't so
> it is confusing to mix the two as you are doing.

Agree.

> 6) Your use of inline keyword for in-class function declaration seems bogus.
>
Indeed. inline is unnecessary here.

Mr Flibble

unread,
Jul 7, 2017, 3:47:36 PM7/7/17
to
On 07/07/2017 16:31, Gareth Owen wrote:
> Mr Flibble <flibbleREM...@i42.co.uk> writes:
>
>> 1) Member data should come after member functions.
>
> Beside "convention", is there any reason for this rule?
>
> My tendency is to group public data and public functions together, so
> the user can see the whole API/contract/"interface" in one place.

Data does not form part of the interface because data that forms part of
the class invariant (that which the interface guarantees) cannot be public.

/Flibble

Daniel

unread,
Jul 7, 2017, 3:48:39 PM7/7/17
to
On Friday, July 7, 2017 at 12:13:30 PM UTC-4, Alf P. Steinbach wrote:
> On 07-Jul-17 3:26 PM, Mr Flibble wrote:
>
> > 6) Your use of inline keyword for in-class function declaration seems
> > bogus.
>
>
> And it tells you that, not as a hint that you'd have to figure out, but
> as absolutely required by the language rules,
>
But the compiler is free to ignore your inline declaration. It's still
only a hint.

Daniel

Mr Flibble

unread,
Jul 7, 2017, 3:55:33 PM7/7/17
to
That is what typedefs are for:

{
private:
typedef vector<string> container_type;
public:
typedef container_type::const_iterator const_iterator;
public:
const_iterator begin() const { return items_.begin(); }
}

No longer brittle and now has value as it is obvious that begin()
returns an iterator of some sort so can be used where iterators are used
(e.g with <algorithm>). We indeed do not care what the actual concrete
iterator type is but we do care that it is an iterator.

>
>
>> 4) Your mixture of capital letter and underscores for class names is
>> egregious.
>
> I capitalize type names.
>
> E.g. in some cases it's convenient to have a variable and a type of the
> same name, just with different capitalization, and also, in some cases
> it's convenient to have a type with the same name as a core language or
> standard library type, except for capitalization. So I've found it to be
> a nice convention. I've used many different conventions over the years.
>
>
>> 5) std::vector::at() can throw whilst std::vector::operator[] doesn't
>> so it is confusing to mix the two as you are doing.
>
> As I see it, the need for superfast indexing of command line arguments
> is non-existent.
>
> Then convenient range-checking can be provided at no cost, so it is. :)
>
> Since it's part of the interface (contract) of this class, it's in the
> interface, and it's hereby proved that that contract is noticed, thanks.

By convention operator[] doesn't throw whilst yours can so your
interface is broken, by convention.

>
>
>> 6) Your use of inline keyword for in-class function declaration seems
>> bogus.
>
> It tells you (very clearly) that the definition of that function is
> and/or should be provided textually inline in header code.
>
> And it tells you that, not as a hint that you'd have to figure out, but
> as absolutely required by the language rules,
>
> except, to be pedantic, that the standard allows code to be provided by
> a database or magic or whatever, not necessarily as files.
>
> The `inline` keyword has to be either on the in-class declaration, or on
> the definition, or both.
>
> Choosing to place it only on the definition would communicate the least,
> the minimum, to a reader of the code, opposite of what I want.

Nope. It's bogus.

/Flibble

Alf P. Steinbach

unread,
Jul 7, 2017, 4:13:13 PM7/7/17
to
On 07-Jul-17 9:33 PM, Alf P. Steinbach wrote:
> On 07-Jul-17 8:38 PM, Manfred wrote:
[snip]
>> If you wish, your library could set up a decent argc/argv set from the
>> Windows command line,
>
> It does.

Oh, I was too hasty there, sorry.

But /now/ it does. :)

At least if this is what you were thinking of:


inline auto command_line() -> string;

class Command_line_args
{
protected:
vector<string> items_;

public:
auto begin() const { return items_.begin(); }
auto end() const { return items_.end(); }

auto size() const -> Size { return items_.size(); }

auto operator[]( Index const i ) const
-> ref_<const string>
{ return items_.at( i ); }

inline Command_line_args(); // Implemented for each
supported platform.
};

class Command_argv_array
: private Command_line_args
{
private:
vector<ptr_<char>> pointers_;

public:
auto argc() const -> int { return size(); }
auto argv() -> ptr_<ptr_<char>> { return &pointers_[0]; }

Command_argv_array( Command_line_args args = {} )
: Command_line_args{ move( args ) }
{
for( ref_<string> s : Command_line_args::items_ )
{
pointers_.push_back( &s[0] );
}
pointers_.push_back( nullptr );
}
};


Cheers!,

- Alf

Alf P. Steinbach

unread,
Jul 7, 2017, 4:18:23 PM7/7/17
to
No, it's absolutely required by the language rules.

The compiler is however, as I understand it, free to not diagnose the
resulting UB if one chooses to ignore the constraint.

C++14 §7.1.2/4:

“An inline function shall be defined in every translation unit in which
it is odr-used and shall have exactly the same definition in every case”

Note the “shall”.

There is no wiggle room, it's an absolute requirement.


Cheers!, & hth.,

- Alf

Alf P. Steinbach

unread,
Jul 7, 2017, 4:22:56 PM7/7/17
to
On 07-Jul-17 9:55 PM, Mr Flibble wrote:
>
> By convention operator[] doesn't throw whilst yours can so your
> interface is broken, by convention.

You mean that `operator[]` often has Undefined Behavior, in the
out-of-range cases where this interface has well-defined behavior.

Note that it's not guaranteed that it won't throw an exception for that UB.

The UB can do anything. ;-)


> [about something] Nope. It's bogus.

Well, I read that as the Fibble denial mode / entertainment trolling. No
offense intended. But otherwise I can't make sense of it.


Cheers!,

- Alf

Mr Flibble

unread,
Jul 7, 2017, 4:27:53 PM7/7/17
to
On 07/07/2017 21:22, Alf P. Steinbach wrote:
> On 07-Jul-17 9:55 PM, Mr Flibble wrote:
>>
>> By convention operator[] doesn't throw whilst yours can so your
>> interface is broken, by convention.
>
> You mean that `operator[]` often has Undefined Behavior, in the
> out-of-range cases where this interface has well-defined behavior.
>
> Note that it's not guaranteed that it won't throw an exception for that UB.
>
> The UB can do anything. ;-)

You are missing the point. By convention I will assume it doesn't throw
so will have to write unnecessary bounds checking code and throw myself
when there is no need to.

>
>
>> [about something] Nope. It's bogus.
>
> Well, I read that as the Fibble denial mode / entertainment trolling. No
> offense intended. But otherwise I can't make sense of it.

Not trolling; your use of the keyword in class declaration is bogus.

I see you conveniently ignored my response re your egregious use of auto
keyword in an API? I will take that as acceptance that I am correct.

/Flibble

Manfred

unread,
Jul 7, 2017, 4:37:30 PM7/7/17
to
On 7/7/2017 9:33 PM, Alf P. Steinbach wrote:
> On 07-Jul-17 8:38 PM, Manfred wrote:
>> e.g. including wildchar expansion and the like.
>
> Yes, I've considered that, thanks!
[...]
> But doing that by default, as MinGW g++ unfortunately does for the
> arguments of `main`, breaks expectation in Windows: it does not conform
> to the convention established by the main compiler for the platform.
I am not that familiar with MinGW, but this probably follows from the
fact that such cmdline preprocessing has been designed to be performed
by the shell, and MinGW tries to emulate it, but it is a different thing.
>
> For example, the Windows / Visual C++ approach allows you to write a
> `fastmove` program that accepts `fastmove *.bah someplace\*.foo`. That
> will just not work with with MinGW g++'s default. And I don't know any
> way to tell MinGW g++ to not do that. :(
If MinGW manages to emulate the shell behaviour properly, then single or
double quoting ('*.bah') would do.
>
[...]
> and the /NoWide/ solution of passing on argc and argv, is abhorrent to
> me (I also suspect that it's simply wrong when pitted against MinGW g++
> and wildcard arguments, but I haven't tested that yet).
>
>
>> A lot could be done in that direction (ref the sh/bash manpage)
>> although I cannot say if it can be worth the effort at all on Windows,
>> given the limited use of cmdline args on this platform.
>
> Command line args are used most every time you “open” a file in Windows,
> e.g. by double-clicking it.
Yes, but still much a more limited use of args, if compared to the other
environment.

[...]
>
> Well I meant the `command_line()` function to produce a possible command
> line that, when used to create a new process, would reproduce exactly
> the command line args here.
This seems to depend on the process creation API: in *nix the exec
family requires arguments specified by different string pointers, so no
quoting needed.
On Windows it depends on how CreateProcess handles the single
lpCommandLine string.

Ian Collins

unread,
Jul 7, 2017, 4:47:11 PM7/7/17
to
On 07/ 8/17 01:26 AM, Mr Flibble wrote:
> On 07/07/2017 12:08, Alf P. Steinbach wrote:
>> It so happens that I don't have any Apple equipment, and since I'm
>> rather poor I can't afford to just buy it.
>>
>> I've just implemented the following declaration for Windows and Linux:
>>
>> <url:
>> https://github.com/alf-p-steinbach/stdlib/blob/master/source/extension/process_command_line.declarations.hpp>
>>
>>
>>
>> inline auto command_line() -> string;
>>
>> class Command_line_args
>> {
>> private:
>> vector<string> items_;
>>
>> public:
>> auto begin() const { return items_.begin(); }
>> auto end() const { return items_.end(); }
>>
>> auto size() const -> Size { return items_.size(); }
>>
>> auto operator[]( Index const i ) const
>> -> ref_<const string>
>> { return items_.at( i ); }
>>
>> inline Command_line_args();
>> };

0) Use of "private:" here is superfluous.

> 1) Member data should come after member functions.
> 2) Private should come after public.
> 3) Your use of auto in a class interface is inappropriate; auto use at
> client site is fine but at API level it just obfuscates: what is the
> fucking return type?
> 4) Your mixture of capital letter and underscores for class names is
> egregious.
> 5) std::vector::at() can throw whilst std::vector::operator[] doesn't so
> it is confusing to mix the two as you are doing.
> 6) Your use of inline keyword for in-class function declaration seems bogus.
>
> /Flibble
>


--
Ian

Alf P. Steinbach

unread,
Jul 7, 2017, 5:24:06 PM7/7/17
to
On 07-Jul-17 10:46 PM, Ian Collins wrote:
> On 07/ 8/17 01:26 AM, Mr Flibble wrote:
>> On 07/07/2017 12:08, Alf P. Steinbach wrote:
>>>
>>> class Command_line_args
>>> {
>>> private:
>
> 0) Use of "private:" here is superfluous.

Generally, explicit is good, implicit is bad, except where you need a
choice to adapt automatically to changes.

As I understand it you would like to have an /implicit/ choice for the
access specifier where it can hurt (e.g., blind insertion of code can
break it) and where it doesn't reduce verbosity, and, judging from your
quote of Leigh's points, you would like to be /explicit/ about the
choice for iterator return type where that is needlessly constraining,
brittle and verbose; in both cases opposite of the code as given.

From my point of view that's a let's-adopt-anti-patterns! mindset.


Cheers!,

- Alf

Daniel

unread,
Jul 7, 2017, 5:26:06 PM7/7/17
to
On Friday, July 7, 2017 at 4:18:23 PM UTC-4, Alf P. Steinbach wrote:
>
> C++14 §7.1.2/4:
>
> “An inline function shall be defined in every translation unit in which
> it is odr-used and shall have exactly the same definition in every case”
>
> Note the “shall”.
>
> There is no wiggle room, it's an absolute requirement.
>
Well, there's wiggling, and then there's wiggling. As I understand it, the
compiler is still free to generate a function call (as opposed substituting
inline substitution) to any function specified as inline, as long as the
rules regarding separate definitions in each translation unit are followed.

Daniel

Alf P. Steinbach

unread,
Jul 7, 2017, 5:48:06 PM7/7/17
to
Yes, the machine code inlining of calls effect of `inline` is just a hint.

The effect that I used `inline` for, quoted above, is not a hint, but an
absolute requirement, “shall”.

It tells any reader of the code, when that reader is familiar with the
language rules, that the function must be or is defined as an `inline`
function, identically in every translation unit, which in practice means
in a header file, and that no linking with separately compiled stuff is
necessary for this function.


Cheers!,

- Alf

Ian Collins

unread,
Jul 7, 2017, 6:00:42 PM7/7/17
to
On 07/ 8/17 09:23 AM, Alf P. Steinbach wrote:
> On 07-Jul-17 10:46 PM, Ian Collins wrote:
>> On 07/ 8/17 01:26 AM, Mr Flibble wrote:
>>> On 07/07/2017 12:08, Alf P. Steinbach wrote:
>>>>
>>>> class Command_line_args
>>>> {
>>>> private:
>>
>> 0) Use of "private:" here is superfluous.
>
> Generally, explicit is good, implicit is bad, except where you need a
> choice to adapt automatically to changes.

In general, idiomatic is good, superfluous verbosity is bad!

Every C++ programmer knows the default access for a class is private and
a struct is public. Would your write

struct X
{
public:

int n;
};

?

I'd put it in the same bucket as the pointless use of "::std"

> As I understand it you would like to have an /implicit/ choice for the
> access specifier where it can hurt (e.g., blind insertion of code can
> break it) and where it doesn't reduce verbosity, and, judging from your
> quote of Leigh's points, you would like to be /explicit/ about the
> choice for iterator return type where that is needlessly constraining,
> brittle and verbose; in both cases opposite of the code as given.

The auto vs alias debate is one my current team often has. I tend
towards auto for simple, in class declaration members (such as your
begin() and end()) and alias elsewhere. I only use suffix return in
templates where it is genuinely useful.

So I don't agree with his third point.

I do completely agree with his objection to using at() in your operator[].

> From my point of view that's a let's-adopt-anti-patterns! mindset.

Superfluous verbosity is the anti-pattern...

--
Ian

Öö Tiib

unread,
Jul 7, 2017, 6:32:26 PM7/7/17
to
On Friday, 7 July 2017 19:13:30 UTC+3, Alf P. Steinbach wrote:
> On 07-Jul-17 3:26 PM, Mr Flibble wrote:
> > 2) Private should come after public.
>
> I have a different and, I believe, just as well-informed opinion.

That is exactly the fun about opinions! ;)

Class members is one of the few places in C++ where declaration order
does not affect the outcome much.

Daniel

unread,
Jul 7, 2017, 7:09:57 PM7/7/17
to
On Friday, July 7, 2017 at 6:32:26 PM UTC-4, Öö Tiib wrote:
> On Friday, 7 July 2017 19:13:30 UTC+3, Alf P. Steinbach wrote:
> > On 07-Jul-17 3:26 PM, Mr Flibble wrote:
> > > 2) Private should come after public.
> >
> > I have a different and, I believe, just as well-informed opinion.
>
> That is exactly the fun about opinions! ;)

Especially fun when they run counter to the received wisdom!

Daniel


Alf P. Steinbach

unread,
Jul 8, 2017, 12:00:06 AM7/8/17
to
On 08-Jul-17 12:00 AM, Ian Collins wrote:
> [snip]
> In general, idiomatic is good, superfluous verbosity is bad!

On further reflection I think you're right here.

So I went trough all (the very few) classes in /stdlib/ and removed
those pesky redundant `private:` at top of each.

This works well with a convention of putting private implementation
stuff first in the class. :)


> Every C++ programmer knows the default access for a class is private and
> a struct is public. Would your write
>
> struct X
> {
> public:
>
> int n;
> };
>
> ?

No, because a `struct` is by convention used for a plain old POD, with
only one access level applied to the whole thing, namely public access.

So, I don't buy this argument, but still you do have a point, I think.


Cheers!,

- Alf

Christian Gollwitzer

unread,
Jul 8, 2017, 12:56:22 AM7/8/17
to
Am 07.07.17 um 13:08 schrieb Alf P. Steinbach:
> It so happens that I don't have any Apple equipment, and since I'm
> rather poor I can't afford to just buy it.
>
> I've just implemented the following declaration for Windows and Linux:
>
> <url:
> https://github.com/alf-p-steinbach/stdlib/blob/master/source/extension/process_command_line.declarations.hpp>
>

In plain English, what on earth does this code do? Why is it needed?
I am reading that it gets you the command line arguments as a
std::vector<string>. In both Linux & OSX the command line arguments come
as the arguments to main, so what are these functions good for?

I'd do:

std::vector<string> cmdline_args;
int main (int argc, const char *argv[]) {
for (int i = 0; i < argc; i++) {
cmdline_args.push_back(argv[i]);
}

// do your stuff here
}



Christian

Mr Flibble

unread,
Jul 8, 2017, 12:58:14 AM7/8/17
to
On 08/07/2017 04:59, Alf P. Steinbach wrote:
> On 08-Jul-17 12:00 AM, Ian Collins wrote:
>> [snip] In general, idiomatic is good, superfluous verbosity is bad!
>
> On further reflection I think you're right here.
>
> So I went trough all (the very few) classes in /stdlib/ and removed
> those pesky redundant `private:` at top of each.

An egregious change to a library with an egregious name.

>
> This works well with a convention of putting private implementation
> stuff first in the class. :)

Hardly a convention if most people put private stuff AFTER public stuff.

/Flibble

Ian Collins

unread,
Jul 8, 2017, 1:09:57 AM7/8/17
to
Why the complexity?

std::vector<std::string> args {argv, argv+argc};

--
Ian

Gareth Owen

unread,
Jul 8, 2017, 2:10:12 AM7/8/17
to
Mr Flibble <flibbleREM...@i42.co.uk> writes:

> Data does not form part of the interface because data that forms part
> of the class invariant (that which the interface guarantees) cannot be
> public.

Mostly true for complex classes, but don't tell me that a simple POD class
like

struct Point {
int x;
int y;
int z;
};

is improved by private data and public accessor functions.
That'd be some Steinbach-esque obfuscation.

Christian Gollwitzer

unread,
Jul 8, 2017, 2:46:58 AM7/8/17
to
Am 08.07.17 um 07:09 schrieb Ian Collins:
Because of my ignorance of this constructor and tricky pointer arithmetics.

Thanks - that is even better.


Christian

Alf P. Steinbach

unread,
Jul 8, 2017, 4:22:49 AM7/8/17
to
On 08-Jul-17 6:55 AM, Christian Gollwitzer wrote:
> Am 07.07.17 um 13:08 schrieb Alf P. Steinbach:
>> It so happens that I don't have any Apple equipment, and since I'm
>> rather poor I can't afford to just buy it.
>>
>> I've just implemented the following declaration for Windows and Linux:
>>
>> <url:
>> https://github.com/alf-p-steinbach/stdlib/blob/master/source/extension/process_command_line.declarations.hpp>
>>
>
> In plain English, what on earth does this code do?

It gets you UTF-8 encoded command line arguments, in a portable way.

The encoding is important for characters outside ASCII's A through Z.


Cheers & hth.,

- Alf

Alf P. Steinbach

unread,
Jul 8, 2017, 4:26:30 AM7/8/17
to
If you point out where you find something of mine obfuscated, I'll try
to clear it up for you.

In spite of that silly name calling.


Cheers!,

- Alf

Gareth Owen

unread,
Jul 8, 2017, 5:51:00 AM7/8/17
to
"Alf P. Steinbach" <alf.p.stein...@gmail.com> writes:

> If you point out where you find something of mine obfuscated, I'll try
> to clear it up for you.

auto main -> int

when *literally* *everyone* *else* writes

int main()

Gratutious, unhelpful, unidiomatic = obfuscated.

> In spite of that silly name calling.

Your code is obfuscated. Its not name call out your obfuscating
affectations as gratuitous obfuscation (and, make no mistake,

"auto main -> int"

is an affectation - it has no benefit whatsover for anyone besides
making you feel smarter, and everyone else roll their eyes at the
idiocy).

Ian Collins

unread,
Jul 8, 2017, 6:08:00 AM7/8/17
to
On my desktop (Solaris) it "just works"..

#include <vector>
#include <string>
#include <iostream>

int main( int argc, char** argv )
{
std::vector<std::string> args {argv, argv+argc};

for( auto arg: args )
{
std::cout << arg << std::endl;
}

return 0;
}

./a.out €
./a.out


--
Ian

Mr Flibble

unread,
Jul 8, 2017, 9:15:26 AM7/8/17
to
That data doesn't contribute to an invariant so it's fine.

/Flibble


Manfred

unread,
Jul 8, 2017, 9:26:24 AM7/8/17
to
That's because it is a good desktop.
(On Fedora Linux it "just works" too)
On Windows (Win10):

C:>arg è
arg
Φ

Alf P. Steinbach

unread,
Jul 8, 2017, 10:17:16 AM7/8/17
to
Well, I can't (or will not) help you with that social issue, sorry.

If it had been something technical, something unclear to you, as you
indicated, then I'd gladly help out in spite of the foul behavior
exhibited above.


Cheers!,

- Alf

Mr Flibble

unread,
Jul 8, 2017, 11:32:14 AM7/8/17
to
You are honestly saying that

auto main()

isn't a mental OCD tick?

Nobody on this entire planet EXCEPT YOU writes:

auto main()

EVERYBODY ELSE on this entire planet writes:

int main()

/Flibble

Mr Flibble

unread,
Jul 8, 2017, 11:38:03 AM7/8/17
to
.. so it is hardly surprising that you use 'auto' in other inappropriate
places too.

/Flibble

Gareth Owen

unread,
Jul 8, 2017, 12:53:36 PM7/8/17
to
"Alf P. Steinbach" <alf.p.stein...@gmail.com> writes:

> Well, I can't (or will not) help you with that social issue, sorry.

Unreadable, correct code *is* a social issue.

Ian Collins

unread,
Jul 8, 2017, 4:59:57 PM7/8/17
to
On 07/ 9/17 02:16 AM, Alf P. Steinbach wrote:
> On 08-Jul-17 11:50 AM, Gareth Owen wrote:
>> "Alf P. Steinbach" <alf.p.stein...@gmail.com> writes:
>>
>>> If you point out where you find something of mine obfuscated, I'll try
>>> to clear it up for you.
>>
>> auto main -> int
>>
>> when *literally* *everyone* *else* writes
>>
>> int main()
>>
>> Gratutious, unhelpful, unidiomatic = obfuscated.
>>
>>> In spite of that silly name calling.
>>
>> Your code is obfuscated. Its not name call out your obfuscating
>> affectations as gratuitous obfuscation (and, make no mistake,
>>
>> "auto main -> int"
>>
>> is an affectation - it has no benefit whatsover for anyone besides
>> making you feel smarter, and everyone else roll their eyes at the
>> idiocy).
>>
>
> Well, I can't (or will not) help you with that social issue, sorry.

You may not appreciate his tone, but he is spot on with this one. You
may well be the only C++ programmer on the planet who writes

auto main() -> int

int main() is so idiomatic anything else is obfuscation. Not only is it
obfuscation, it's more typing!

--
Ian

Öö Tiib

unread,
Jul 8, 2017, 5:38:53 PM7/8/17
to
Yes, everybody agree with "int main()" being idiomatic in C++ and that Alf
adds some redundant characters there but it is still valid C++ what he
writes. Sort of like that "::std" of woodbrian is valid C++.

Note that the new "wannabe better C++" languages tend to have return
type of function indicated at end, so it is sort of "trendy" what Alf does.

Swift:
func greet(person: String) -> String {
let greeting = "Hello, " + person + "!"
return greeting
}

Go:
func add(x int, y int) int {
return x + y
}

Rust:
fn add_one(x: i32) -> i32 {
x + 1
}


Christian Gollwitzer

unread,
Jul 8, 2017, 5:39:10 PM7/8/17
to
Am 08.07.17 um 15:26 schrieb Manfred:
> On 7/8/2017 12:07 PM, Ian Collins wrote:
>> On 07/ 8/17 08:22 PM, Alf P. Steinbach wrote:
>>> It gets you UTF-8 encoded command line arguments, in a portable way.
>>>
>> On my desktop (Solaris) it "just works"..
>>
>> #include <vector>
>> #include <string>
>> #include <iostream>
>>
>> int main( int argc, char** argv )
>> {
>> std::vector<std::string> args {argv, argv+argc};
>>
>> for( auto arg: args )
>> {
>> std::cout << arg << std::endl;
>> }
>>
>> return 0;
>> }
>>
>> ./a.out €
>> ./a.out
>> €
>>
> That's because it is a good desktop.
> (On Fedora Linux it "just works" too)
> On Windows (Win10):
>
> C:>arg è
> arg
> Φ

That's exactly the point. It must be fixed for Windows, maybe, because
that is a stupid OS. For almost anything else it "just works" - why does
Alf muck around with /proc/self and tokenize the stream etc.? That makes
absolutely no sense.

Christian

Ian Collins

unread,
Jul 8, 2017, 7:20:37 PM7/8/17
to
Maybe, but in C++ main is a bit of an oddball in requiring an explicit
return type.

I consider the use of auto fine when a suffix return isn't required (C++
is more elegant than these other languages in that regard) but outside
of template code, it is more trouble than it is worth.


--
Ian

Alf P. Steinbach

unread,
Jul 8, 2017, 7:35:32 PM7/8/17
to
On 08-Jul-17 11:39 PM, Christian Gollwitzer wrote:
> Am 08.07.17 um 15:26 schrieb Manfred:
>> [snip]
>> That's because it is a good desktop.
>> (On Fedora Linux it "just works" too)
>> On Windows (Win10):
>>
>> C:>arg è
>> arg
>> Φ
>
> That's exactly the point. It must be fixed for Windows, maybe, because
> that is a stupid OS. For almost anything else it "just works" - why does
> Alf muck around with /proc/self and tokenize the stream etc.?

Because /fixing/ it for Windows, in a reliable way, appears to be
impossible. The immediate showstopper for that is that MinGW g++ doesn't
pass `__argc` and `__argv` to `main`, as Visual C++ does. But even if it
did, some other compiler might deviate from the platform convention.

So /stdlib/ provides an alternative, `Command_line_args`.

And for maximum portability until default construction of
`Command_line_args` is in place also for macOS and more OSes (hopefully
someone will help me make that happen!) I've added a portable fallback
solution, namely a factory function `Command_line_args::from_os_or_from`
(main args) that requires access to the `main` arguments. By requiring
this access it cannot be used where one does not have those `main`
arguments readily available, e.g. with a main function called by a
library supplied `main`. But on the other hand, most *nix-land code is
structured so that those arguments are accessible, proving that passing
those `main` arguments around is doable, even if unclean.

<url:
https://github.com/alf-p-steinbach/stdlib/#background-goal--degree-of-goal-achievement>

… provides some background and example programs.

Mr Flibble

unread,
Jul 8, 2017, 10:30:10 PM7/8/17
to
On 09/07/2017 00:35, Alf P. Steinbach wrote:
> So /stdlib/ provides an alternative, `Command_line_args`.

"stdlib"? What an egregious and egotistic name for a toy hobby project
library.

/Flibble

Daniel

unread,
Jul 8, 2017, 10:47:42 PM7/8/17
to
At least with that he's not a minority of one, as he is for auto main -> int
:-)

Mr Flibble

unread,
Jul 9, 2017, 2:13:25 AM7/9/17
to

Gareth Owen

unread,
Jul 9, 2017, 2:46:40 AM7/9/17
to
Öö Tiib <oot...@hot.ee> writes:

> Yes, everybody agree with "int main()" being idiomatic in C++ and that Alf
> adds some redundant characters there but it is still valid C++ what he
> writes. Sort of like that "::std" of woodbrian is valid C++.

If there were any question of its validity, I would have chosen a word
other than "obfuscation". Obfuscation implicitly admits correctness.

Öö Tiib

unread,
Jul 9, 2017, 8:11:31 AM7/9/17
to
I did not want to imply that anyone had opinion that Alf's code is invalid.
To me obfuscated means that it is hard to read and hard to maintain and
that validity is orthogonal to it. Therefore I just noted that it is valid.
Even "obfuscation" feels somewhat too strong about it. Redundant 6
characters do not make it hard to maintain. The redundancy is at about
level of writing "if(x==true)" instead of "if(x)".

Chris Vine

unread,
Jul 9, 2017, 10:20:14 AM7/9/17
to
On Sun, 9 Jul 2017 05:11:06 -0700 (PDT)
Öö Tiib <oot...@hot.ee> wrote:
[snip]
> The redundancy is at about level of writing "if(x==true)" instead of
> "if(x)".

If 'x' is anything other than of boolean type, the first is not a
redundantly elongated version of the second. They are different. For
the naive programmer, where 'x' is an integer 'if(x==true)' might well
be a mistake. It is in any event a bad habit to get into.

Christiano

unread,
Jul 13, 2017, 6:50:15 AM7/13/17
to
On 07/07/17 08:08, Alf P. Steinbach wrote:
> It so happens that I don't have any Apple equipment

When I had a similar problem, I bought 1 month of VPS Mac here:
http://hostmyapple.com/

And I used the free program RealVNC to access the VPS (and SSH as well).

0 new messages