On Tue, 19 Apr 2016 20:51:52 +0200
Klemens Morgenstern
Am 19.04.2016 um 20:08 schrieb Niall Douglas:
On 19 Apr 2016 at 13:34, Klemens Morgenstern wrote:
[...]
A freeform constructor with tagged parameters is absolutely right for when the parameters can be extended by third party code. Here though parameter types are completely known, so the appropriate design for when there are too many parameters and/or you'd like to name them is to pass a tagged tuple aka a struct.
The choice to use metaprogramming should always confer an absolute design win over all other design alternatives given the increased compile times, memory usage, brittleness and other factors. Metaprogramming is very much not free of cost. It should be used as sparingly as possible in publicly facing library APIs.
In particular I find Process' use of a freeform constructor gratuitous given the much simpler close substitutes like passing a struct.
Well, it doesn't seem like we'll agree any time soon, but that's imho the beauty of open-source. If you have any design for a process library, I would be very much interested in it.
Btw: boost.process 0.5 only allowed initializers to be passed to the execute function, i.e. you had to write
execute(set_exe("gcc"), set_args({"--version"});
I intentionally changed that, so one could write
execute("gcc", "--version");
because I find this much more intuitive (i.e. design win). This allows more parameter to be passed, like std::error_code or boost::asio::io_service. And unlike your proposed "make everything async" solution, you only pay for it, if you use it. I could add an exe_args initializer, so you can get rid of the initializer building altogether.
`execute` is a function that takes `T&&...`, but certain types are going to fail internally. For example, the `execute` signature allows for zero arguments which does not make sense. And what advantage is there to making the first argument templated instead of a `const char*`? Is there an operating system that takes an argument other than a null-terminated c-style string for the command parameter? It is easy to provide forwarding overloads for other types such as boost::filesystem. And it would be nice if the command-line arguments to the process were not intermingled with the options. What if instead of `execute` you had a function `command` that returned a callable with overloads for `operator|`, `operator<`, and `operator>`: (command("echo", "-n", "some text") > "foo.txt")(options...) (command("wget", url) | command("sha256sum") > ostream))() Which I _think_ has the desired precedence (relational before `|`). In fact, why not include `||` and `&&` - is this too crazy? The immediate invocation of each operand is irrelevant to this use case. Also, the returned object could _always_ be a nullary-callable, but with named parameters for modifying options. I would consider converting static functions into constexpr functors if they are templated - or at least the `execute` function. This would make the functions in the library easier to use with std::bind and boost::fit which might be useful. Lee