Boost logo

Boost :

From: Rob Stewart (stewart_at_[hidden])
Date: 2005-01-11 13:18:50


From: christopher diggins <cdiggins_at_[hidden]>
> From: "Jonathan Turkanis" <technews_at_[hidden]>
>
> >> void DoWork() {
> >> // do work
> >> }
> >>
> >> int main() {
> >> DoWork();
> >> }
> >
> > Okay, but do you really expect people to start writing programs this way?
>
> Yes, especially if the iostreams library provides the functionality to them.
> My point is that C++ code is pointlessly hard to reuse as is, and I am
> pushing for new ways to make small programs more reusable. This is incrediby
> important when managing large numbers of small programs (for instance
> library tests and demos). It is trivial to refactor code to make it look
> like the above, just cut and paste the main!

You assume that nothing fails in the above, since main() falls
through and, therefore, returns zero. Are you proposing that
main() should actually catch exceptions and, possibly, extract
its exit status from the exception object?

> > I
> > think people would only do this to conform to your filter concept. My
> > question
> > is: why aren't the other concepts sufficient?
>
> The other concepts are fine, they are just more obfuscated than most
> programmers require. Just imagine trying to explain how to use a filter

You've admitted to being relatively new to C++. Can you rightly
determine what "most programmers require?"

> concept in a way which makes sense to a Java / Delphi / C programmer. I
> think it is important to try and provide alternatives where possible which
> makes sense to professional programmers who may not be familiar with the
> intricacies of generic programming techniques and functors.

A reasonable goal, though all C++ programmers need to become
familiar with generic programming and function objects. These
really aren't novel or academic techniques.

> > I guess I should have asked for a *realistic* example. If you really write
> > such
> > simple programs you don't have to worry about reuse; it's simpler to write
> > the
> > whole program again from scratch.
>
> First off I do write programs as simple as that and I have a lot of them.

In the *nix tradition, such simple filters are exactly what's
desirable, at least for assembly into pipelines.

> This occurs frequently for testing, prototypes, demos, and systems admin. I
> strongly disagree with maintaining multiple code bases, rather than
> refactoring and reusing the code. As a professional coder I am always
> looking for ways to be more productive and and have less code to manage.

I think Jonathan meant that a program as simple as your toupper
example would more likely be written as a library function, to be
reused in other programs, than as a standalone program.

> Nonetheless, I do currently have a non-trivial program which converts C++
> into a <pre></pre> html tag, CppToHtmlPreTag, it operates obviously on the
> stdin and outputs to stdout. It looks essentially like this:
>
> void CppToHtmlPreTag() {
> // calls multiple other functions to do the work
> };
>
> int main() {
> CppToHtmlPreTag();
> return 0;
> }

So the result of this program is to write "<PRE>" to stdout, copy
stdin to stdout, and write "</PRE>"? Why do you need a program
for that? I can see needing a general purpose program for
copying stdin to stdout such that a script can print/echo
"<PRE>", call the no-op filter, and then print/echo "</PRE>" as
well as other variations. You could even write a general purpose
program that took two arguments -- strings -- that it writes
before and after copying stdin to stdout.

On *nix, that "general purpose program for copying stdin to
stdout" could be awk:

   #!/bin/sh
   echo "<PRE>"
   awk '{print}'
   echo "</PRE>"

A "general purpose program that took two arguments -- strings --
that it writes before and after copying stdin to stdout" can be,
on *nix:

   #!/bin/sh
   if test -n "$1"; then
      echo "$1"
   fi
   awk '{print}'
   if test -n "$2"; then
      echo "$2"
   fi

The point is that there are several approaches to your simple
goal that don't involve something as complex as you've built, and
yet provides all of the benefits.

Another approach is something like Microsoft's rundll32.exe which
loads a DLL, locates a named entry point, and then passes some
arguments to it. If the function signature requirements are a
problem, you could create your own version.

Assembling your chain would involve a batch/command file that
calls rundll32.exe (or your tool) as many times as needed using
the shell's I/O redirection to assemble the pieces.

IOW, I don't think I see the value in rewriting existing code to
conform to your filter's interface such that it can be assembled
into a pipeline via C++ when pipelining is a forte of the shell
(at least *nix shells).

> I want to reuse this program in another program which outputs an entire Html
> Docucment with a header and footer. ( CppToHtmlDoc ). The easiest way I can
> think of to do this is to write a new program such as (this is to a certain
> degree psuedo-code):
>
> struct CppToHtmlDoc {
> CppToHtmlDoc(string css, string title) : mCss(css), mTitle(title);
> void filter() {
> cout << "<html><head><title>" << mTitle;
> cout << "</title><link rel='stylesheet' type='text/css' href='";
> cout << mCss << "'/><body>"
> cin | CppToHtmlPreTag();
> cout << "</body></html>";
> }
> string mCss;
> string mTitle
> }
>
> int main(int argc, char** argv) {
> assert(argc == 4);
> CppToHtmlDoc(argv[1], argv[2]) | filestream(argv[3]);
> }
>
> So I wrote program2 using the [b] approach you outlined which I agree that
> it is superior for this program. I also managed to retain my original code
> precisely as is using the [a] approach. If I had to rewrite the original
> program to use a filter concept I would have had to rewrite *all* of my
> functions to pass the the Source and Sink types to each one, and to use src
> and snk instead of cin / cout.

This would be even easier to assemble via scripting and you don't
need to compile anything or maintain source and binaries
independently.

> I guess my point here is that I am able to refactor existing code more
> easily and quickly if you support [a] and [b] syntax. [c] is perfectly
> acceptable, and has its advantages in several scenarios, even though it is
> overkill for my work.

That argument is even stronger for using scripting to assemble
such building blocks.

> I just want to be able to write:
>
> filter1() | filter2();
>
> as a statement, with the implicit understanding it pumps from cin and to
> cout.

You can do that if "filter1" and "filter2" are filter
applications:

   #!/bin/sh
   filter1 | filter2

With that, you didn't have to make any changes to filter1 or
filter2 to be able to form a pipeline. That's even simpler!

-- 
Rob Stewart                           stewart_at_[hidden]
Software Engineer                     http://www.sig.com
Susquehanna International Group, LLP  using std::disclaimer;

Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk