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

Onwards and upwards

1,846 views
Skip to first unread message

woodb...@gmail.com

unread,
Sep 29, 2014, 3:23:49 PM9/29/14
to
I'm working on an on line code generator called the
C++ Middleware Writer. If you have some thoughts on
how to improve the software or documentation on my
site, please let me know. I'll post some files here.
Thanks in advance.

The following is the contents of platforms.hh

#pragma once

#if defined(_MSC_VER) || defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__CYGWIN__)
#define CMW_WINDOWS
#include <ErrorWords.hh>
#include <winsock2.h>
#include <ws2tcpip.h>
using sock_type = SOCKET;
using file_type = HANDLE;

inline int GetError () { return WSAGetLastError(); }

inline void windows_start ()
{
WSADATA wsa;
int rc=WSAStartup(MAKEWORD(2,2),&wsa);
if(0!=rc)throw cmw::failure("WSAStartup: ")<<rc;
}

#else

#include <errno.h>
using sock_type = int;
using file_type = int;

inline int GetError () { return errno; }
inline void windows_start () {}

#endif


Brian
Ebenezer Enterprises - In G-d we trust.
http://webEbenezer.net

Mr Flibble

unread,
Sep 29, 2014, 3:50:50 PM9/29/14
to
Only got one comment: use boost.asio and get rid of all that crap.

/Flibble

woodb...@gmail.com

unread,
Sep 30, 2014, 1:08:39 AM9/30/14
to
On Monday, September 29, 2014 2:50:50 PM UTC-5, Mr Flibble wrote:
>
> Only got one comment: use boost.asio and get rid of all that crap.
>

The C++ Middleware Writer is an alternative to the
serialization library in Boost more so than asio.


Brian
Ebenezer Enterprises
http://webEbenezer.net

Mr Flibble

unread,
Sep 30, 2014, 1:33:56 PM9/30/14
to
On 30/09/2014 06:08, woodb...@gmail.com wrote:
> On Monday, September 29, 2014 2:50:50 PM UTC-5, Mr Flibble wrote:
>>
>> Only got one comment: use boost.asio and get rid of all that crap.
>>
>
> The C++ Middleware Writer is an alternative to the
> serialization library in Boost more so than asio.

That is no reason to not use boost.asio; boost.asio is for networking
not serialization.

Rule of thumb for modern software development: as much as your code as
possible should be portable so get rid of that Winsock shite and use
boost.asio.

/Flibble

Christopher Pisz

unread,
Sep 30, 2014, 3:33:16 PM9/30/14
to
I don't particularly enjoy debugging boost.asio, but haven't really
heard of anyone getting around that with iocp. Who started the thread,
is hard to find out.

Öö Tiib

unread,
Sep 30, 2014, 5:29:26 PM9/30/14
to
Sometimes it is indeed difficult to debug modern C++ if all types
around of where something breaks are whole page of "<", "::" and ">"
nausea far worse than worst of XML. There is alternatively a C
library named "libuv" (part of "node.js" but may be used separately)
that is somewhat similar to boost.asio and that people use for
networking quite finely.

woodb...@gmail.com

unread,
Sep 30, 2014, 9:39:35 PM9/30/14
to
I have some code in my library that's similar to the asio
library. I hope to keep developing this code.

It shouldn't be too hard to make C++ Middleware Writer
code work with asio, but I haven't ever tried it.

My approach is kind of similar to libuv except that I've
used C++.

woodb...@gmail.com

unread,
Sep 30, 2014, 10:06:52 PM9/30/14
to
On Tuesday, September 30, 2014 12:33:56 PM UTC-5, Mr Flibble wrote:
>
> That is no reason to not use boost.asio; boost.asio is for networking
> not serialization.
>
> Rule of thumb for modern software development: as much as your code as
> possible should be portable

I have two things: a library, and a 3-tier system.
Each of the tiers links with the library. The back
tier isn't meant to be very portable. Currently
it's running on BSD. The middle tier is portable
to a number of platforms, and the front tier, which
is the smallest, is meant to be very portable. The
library, front tier and generated code are meant to
be highly portable, and I believe they are.


Brian
Ebenezer Enterprises - So far G-d has helped us.
http://webEbenezer.net

Mr Flibble

unread,
Oct 1, 2014, 1:13:54 PM10/1/14
to
On 01/10/2014 03:06, woodb...@gmail.com wrote:
> On Tuesday, September 30, 2014 12:33:56 PM UTC-5, Mr Flibble wrote:
>>
>> That is no reason to not use boost.asio; boost.asio is for networking
>> not serialization.
>>
>> Rule of thumb for modern software development: as much as your code as
>> possible should be portable
>
> I have two things: a library, and a 3-tier system.
> Each of the tiers links with the library. The back
> tier isn't meant to be very portable. Currently
> it's running on BSD. The middle tier is portable
> to a number of platforms, and the front tier, which
> is the smallest, is meant to be very portable. The
> library, front tier and generated code are meant to
> be highly portable, and I believe they are.

Using Winsock doesn't sound very portable to me.

/Flibble

woodb...@gmail.com

unread,
Oct 1, 2014, 9:57:33 PM10/1/14
to
On Wednesday, October 1, 2014 12:13:54 PM UTC-5, Mr Flibble wrote:
>
> Using Winsock doesn't sound very portable to me.
>

I believe the asio library also uses Winsock on
Windows.

Mr Flibble

unread,
Oct 2, 2014, 1:42:54 PM10/2/14
to
On 02/10/2014 02:57, woodb...@gmail.com wrote:
> On Wednesday, October 1, 2014 12:13:54 PM UTC-5, Mr Flibble wrote:
>>
>> Using Winsock doesn't sound very portable to me.
>>
>
> I believe the asio library also uses Winsock on
> Windows.

Of course it does and std::thread will also use a Windows thread on
Windows so what is your point? boost.asio hides winsock from you so you
can write portable code. Another reason to use boost.asio is that it is
likely that it will go into next major revision of C++.

/Flibble

woodb...@gmail.com

unread,
Oct 2, 2014, 2:52:32 PM10/2/14
to
On Thursday, October 2, 2014 12:42:54 PM UTC-5, Mr Flibble wrote:
>
> Of course it does and std::thread will also use a Windows thread on
> Windows so what is your point? boost.asio hides winsock from you so you
> can write portable code. Another reason to use boost.asio is that it is
> likely that it will go into next major revision of C++.
>

I don't consider asio to be beyond competition and
some of what's in the standard isn't very good.

Mr Flibble

unread,
Oct 2, 2014, 3:55:53 PM10/2/14
to
On 02/10/2014 19:52, woodb...@gmail.com wrote:
> On Thursday, October 2, 2014 12:42:54 PM UTC-5, Mr Flibble wrote:
>>
>> Of course it does and std::thread will also use a Windows thread on
>> Windows so what is your point? boost.asio hides winsock from you so you
>> can write portable code. Another reason to use boost.asio is that it is
>> likely that it will go into next major revision of C++.
>>
>
> I don't consider asio to be beyond competition and
> some of what's in the standard isn't very good.

Stop reinventing a not very good wheel mate. Use boost.asio; abstract
it if you like (I do).

/Flibble

woodb...@gmail.com

unread,
Oct 2, 2014, 11:20:33 PM10/2/14
to
On Thursday, October 2, 2014 2:55:53 PM UTC-5, Mr Flibble wrote:
>
> Stop reinventing a not very good wheel mate. Use boost.asio; abstract
> it if you like (I do).
>

I'm willing to support someone who wants to use
the C++ Middleware Writer (CMW) and asio together.

I'll donate 16 hours/week for six months to a project that
uses the CMW.

Also we'll pay $999 and give a $1,000 investment in Ebenezer
Enterprises to someone who helps us find someone interested
in this. We'll pay the $999 after working for four months
on the project. Ebenezer Enterprises works to reward
investments to 3 times the original amount. So the investment
would result in between $0 and $3,000, depending on how
things go for the company.

Mr Flibble

unread,
Oct 3, 2014, 8:31:45 AM10/3/14
to
That's not how company ownership works mate: if I invest in a company I
expect to own a percentage of it and it's profits.

/Flibble

woodb...@gmail.com

unread,
Oct 3, 2014, 12:24:53 PM10/3/14
to
"The earth is the L-rd's, and everything in it,
the world, and all who live in it;" Psalms 24:1

Potential financial reward is all we promise.

I'm a manager/steward of the company.

woodb...@gmail.com

unread,
Oct 5, 2014, 11:17:52 PM10/5/14
to

I tried rewriting this:

bool found=false;
for(auto const& acct:accounts)
if(acct.number==request.accountNbr){found=true;break;}
if(!found)throw failure("The following account number is not logged in: ")
<<request.accountNbr.value;

using a lambda:

if(::std::none_of(accounts.begin(),accounts.end()
,[&] (cmw_account_info const& a){return a.number==request.accountNbr;}))
throw failure("The following account number is not logged in: ")
<<request.accountNbr.value;

The two versions have the same text size according to the
size command. I think the first version is easier to understand.

Charles J. Daniels

unread,
Oct 6, 2014, 9:50:10 PM10/6/14
to
I like the none_of approach -- it makes it very clear you you throw an error if none_of the given container match something.

To make it even more clear, you could capture the lambda to an auto variable. I like that style. Like this:

auto matchesLoggedInUser = [&] (cmw_account_info const& a){
return a.number==request.accountNbr;
};
if(none_of(accounts.begin(),accounts.end(), matchesLoggedInUser))
throw failure...

Jorgen Grahn

unread,
Oct 7, 2014, 5:26:20 AM10/7/14
to
On Tue, 2014-10-07, Charles J. Daniels wrote:
> On Sunday, October 5, 2014 8:17:52 PM UTC-7, woodb...@gmail.com wrote:
>> I tried rewriting this:
>>
>>
>> bool found=false;
>> for(auto const& acct:accounts)
>> if(acct.number==request.accountNbr){found=true;break;}
>> if(!found)throw failure("The following account number is not logged in: ")
>> <<request.accountNbr.value;
>>
>> using a lambda:
>>
>> if(::std::none_of(accounts.begin(),accounts.end()
>> ,[&] (cmw_account_info const& a){return a.number==request.accountNbr;}))
>> throw failure("The following account number is not logged in: ")
>> <<request.accountNbr.value;
>>
>> The two versions have the same text size according to the
>> size command. I think the first version is easier to understand.

> I like the none_of approach -- it makes it very clear you you throw an error if none_of the given container match something.
>
> To make it even more clear, you could capture the lambda to an auto variable. I like that style. Like this:
>
> auto matchesLoggedInUser = [&] (cmw_account_info const& a){
> return a.number==request.accountNbr;
> };
> if(none_of(accounts.begin(),accounts.end(), matchesLoggedInUser))
> throw failure...

Yeah. In fact, Stroustrup spends a lot of text (in TC++PL) trying to
make people use lambdas when appropriate, but not necessarily stuff
them into long and complicated multi-line expressions.

/Jorgen

--
// Jorgen Grahn <grahn@ Oo o. . .
\X/ snipabacken.se> O o .

woodb...@gmail.com

unread,
Oct 7, 2014, 2:58:34 PM10/7/14
to
On Monday, October 6, 2014 8:50:10 PM UTC-5, Charles J. Daniels wrote:
>
> I like the none_of approach -- it makes it very clear you you throw an error if none_of the given container match something.
>
> To make it even more clear, you could capture the lambda to an auto variable. I like that style. Like this:
>
> auto matchesLoggedInUser = [&] (cmw_account_info const& a){
> return a.number==request.accountNbr;
> };
>
> if(none_of(accounts.begin(),accounts.end(), matchesLoggedInUser))
> throw failure...

That's better, but I don't like having cmw_account_info in
there. The original doesn't need that and it looks to me
like a hindrance.

Öö Tiib

unread,
Oct 7, 2014, 7:48:09 PM10/7/14
to
To me that 'matchesLoggedInUser' feels a bit misleading, I would
use 'isAccountOfRequest'. However 'cmw_account_info'? It is such
average name, only half of it is meaningless bloat and nothing
is misleading. Tolerable. Try sometimes some real fluff names like
'cmw_account_item_data_storage' ... those you will hate. ;)

Charles J. Daniels

unread,
Oct 8, 2014, 1:13:09 AM10/8/14
to
Generic lambdas, part of C++14 which I've not worked with, would allow use of auto over the specific type, if I understand correctly. That would mirror your preferred implementation. There are already existing compilers that can handle such as a thing is also my understanding, including MSVC.

Jorgen Grahn

unread,
Oct 9, 2014, 3:52:50 AM10/9/14
to
On Tue, 2014-10-07, 嘱 Tiib wrote:
> On Tuesday, 7 October 2014 21:58:34 UTC+3, woodb...@gmail.com wrote:
...

> However 'cmw_account_info'? It is such
> average name, only half of it is meaningless bloat and nothing
> is misleading. Tolerable.

I sometimes use the word "info" myself in variable and type names, but
it's a small warning flag. E.g. is there a difference between a CMW
Account object and the object carrying /info/ about a CMW Account?

More direct wording is better; it helps you think.

woodb...@gmail.com

unread,
Oct 9, 2014, 9:23:06 PM10/9/14
to
On Wednesday, October 8, 2014 12:13:09 AM UTC-5, Charles J. Daniels wrote:
>
>
> Generic lambdas, part of C++14 which I've not worked with, would allow use of auto over the specific type, if I understand correctly. That would mirror your preferred implementation. There are already existing compilers that can handle such as a thing is also my understanding, including MSVC.

Normally I'd have access to some compilers that have
support for that but I switched from Linux to BSD
recently and have clang 3.3. Anyway, good to know
about that. I'm not using anything from the algorithm
header currently so would have to add that to get none_of.
On a Linux machine I used the -E option with g++ and
found that including algorithm results in 46,288 lines.
That's a lot of overhead for such a small function.

woodb...@gmail.com

unread,
Oct 17, 2014, 2:08:05 AM10/17/14
to

We're approaching the 12 year mark for CMW being
on line. I believe the CMW was the first on line
C++ code generator.

I have time to make improvements to the software
and docs so don't be shy.

woodb...@gmail.com

unread,
Nov 4, 2014, 12:42:46 PM11/4/14
to
On Friday, October 17, 2014 1:08:05 AM UTC-5, woodb...@gmail.com wrote:
> We're approaching the 12 year mark for CMW being
> on line. I believe the CMW was the first on line
> C++ code generator.
>
> I have time to make improvements to the software
> and docs so don't be shy.
>

I'm afraid the community is missing out on an
opportunity here.

woodb...@gmail.com

unread,
Nov 6, 2014, 12:15:48 PM11/6/14
to
I was reviewing some code and believe I found a problem.

template <class T, class B>
void complexMarshal (B& buf, ::std::complex<T> const& cmplx)
{
buf.Receive(cmplx.real());
buf.Receive(cmplx.imag());
}

// No problem yet

template <class T, class B>
::std::complex<T> complexGive (B& buf)
{
return ::std::complex<T>(buf.template Give<T>(), buf.template Give<T>());
}

There though since the order of evaluation of the
arguments isn't defined it could stick the value for
real into the imaginary field and vice versa. I've
read about this issue for years, but never had to deal
with it until now.

Here's the way I've thought of to fix it:

template <class T, class B>
::std::complex<T> complexGive (B& buf)
{
auto rl = buf.template Give<T>();
return ::std::complex<T>(rl, buf.template Give<T>());
}

Is there a better way to fix it? And how about a suggestion
for a comment to help prevent someone from accidentally
undoing the fix?

Mr Flibble

unread,
Nov 6, 2014, 2:18:54 PM11/6/14
to
On 06/11/2014 17:15, woodb...@gmail.com wrote:
> I was reviewing some code and believe I found a problem.
>
> template <class T, class B>
> void complexMarshal (B& buf, ::std::complex<T> const& cmplx)
> {
> buf.Receive(cmplx.real());
> buf.Receive(cmplx.imag());
> }
>
> // No problem yet
>
> template <class T, class B>
> ::std::complex<T> complexGive (B& buf)
> {
> return ::std::complex<T>(buf.template Give<T>(), buf.template Give<T>());
> }
>
> There though since the order of evaluation of the
> arguments isn't defined it could stick the value for
> real into the imaginary field and vice versa. I've
> read about this issue for years, but never had to deal
> with it until now.
>
> Here's the way I've thought of to fix it:
>
> template <class T, class B>
> ::std::complex<T> complexGive (B& buf)
> {
> auto rl = buf.template Give<T>();
> return ::std::complex<T>(rl, buf.template Give<T>());
> }

A proper fix would be to have "Give()" use an out parameter rather than
a return value thereby preventing the problem from occurring in the
first place. A nice side-effect of this way of doing things is that you
don't need that horrible extra template keyword syntax as T can be
deduced from the output argument.

/Flibble

woodb...@gmail.com

unread,
Nov 6, 2014, 2:31:14 PM11/6/14
to
On Thursday, November 6, 2014 1:18:54 PM UTC-6, Mr Flibble wrote:
> On 06/11/2014 17:15, woodb...@gmail.com wrote:
> >
> > template <class T, class B>
> > ::std::complex<T> complexGive (B& buf)
> > {
> > return ::std::complex<T>(buf.template Give<T>(), buf.template Give<T>());
> > }
> >
> > There though since the order of evaluation of the
> > arguments isn't defined it could stick the value for
> > real into the imaginary field and vice versa. I've
> > read about this issue for years, but never had to deal
> > with it until now.
> >
> > Here's the way I've thought of to fix it:
> >
> > template <class T, class B>
> > ::std::complex<T> complexGive (B& buf)
> > {
> > auto rl = buf.template Give<T>();
> > return ::std::complex<T>(rl, buf.template Give<T>());
> > }
>
> A proper fix would be to have "Give()" use an out parameter rather than
> a return value thereby preventing the problem from occurring in the
> first place.

I think that would have the same problem.

Mr Flibble

unread,
Nov 6, 2014, 2:45:59 PM11/6/14
to
On 06/11/2014 19:31, woodb...@gmail.com wrote:
> On Thursday, November 6, 2014 1:18:54 PM UTC-6, Mr Flibble wrote:
>> On 06/11/2014 17:15, woodb...@gmail.com wrote:
>>>
>>> template <class T, class B>
>>> ::std::complex<T> complexGive (B& buf)
>>> {
>>> return ::std::complex<T>(buf.template Give<T>(), buf.template Give<T>());
>>> }
>>>
>>> There though since the order of evaluation of the
>>> arguments isn't defined it could stick the value for
>>> real into the imaginary field and vice versa. I've
>>> read about this issue for years, but never had to deal
>>> with it until now.
>>>
>>> Here's the way I've thought of to fix it:
>>>
>>> template <class T, class B>
>>> ::std::complex<T> complexGive (B& buf)
>>> {
>>> auto rl = buf.template Give<T>();
>>> return ::std::complex<T>(rl, buf.template Give<T>());
>>> }
>>
>> A proper fix would be to have "Give()" use an out parameter rather than
>> a return value thereby preventing the problem from occurring in the
>> first place.
>
> I think that would have the same problem.

Think again.

/Flibble

woodb...@gmail.com

unread,
Nov 6, 2014, 9:10:05 PM11/6/14
to
On Thursday, November 6, 2014 1:18:54 PM UTC-6, Mr Flibble wrote:
> On 06/11/2014 17:15, woodb...@gmail.com wrote:
> > I was reviewing some code and believe I found a problem.
> >
> > template <class T, class B>
> > void complexMarshal (B& buf, ::std::complex<T> const& cmplx)
> > {
> > buf.Receive(cmplx.real());
> > buf.Receive(cmplx.imag());
> > }
> >
> > // No problem yet
> >
> > template <class T, class B>
> > ::std::complex<T> complexGive (B& buf)
> > {
> > return ::std::complex<T>(buf.template Give<T>(), buf.template Give<T>());
> > }
> >
> > There though since the order of evaluation of the
> > arguments isn't defined it could stick the value for
> > real into the imaginary field and vice versa. I've
> > read about this issue for years, but never had to deal
> > with it until now.
> >
> > Here's the way I've thought of to fix it:
> >
> > template <class T, class B>
> > ::std::complex<T> complexGive (B& buf)
> > {
> > auto rl = buf.template Give<T>();
> > return ::std::complex<T>(rl, buf.template Give<T>());
> > }
>
> A proper fix would be to have "Give()" use an out parameter rather than
> a return value thereby preventing the problem from occurring in the
> first place.

One thing I like about the approach that returns a value
is it can be used in an initializer list.


Brian
Ebenezer Enterprises - "In the L-rd I take refuge" Psalms 11:5
http://webEbenezer.net

Mr Flibble

unread,
Nov 7, 2014, 8:54:31 AM11/7/14
to
The only other option is using some kind of lazy evaluation hack; apart
from that I can think of no way to prevent that type of bug reoccurring
(apart from using out parameters of course).

/Flibble

woodb...@gmail.com

unread,
Nov 7, 2014, 9:57:09 AM11/7/14
to
How about defining the order of evaluation as either
left-to-right or right-to-left?

Mr Flibble

unread,
Nov 7, 2014, 11:56:03 AM11/7/14
to
You mean change C++? Don't be silly.

/Flibble


Öö Tiib

unread,
Nov 7, 2014, 4:49:47 PM11/7/14
to
The iostream-style chaining of operations is also option. That takes
turning brian's logic from "buf" "giving" things to "stuff" into
"stuff" "taking" things out of "buf". Also chaining free functions
looks ugly so either he has to make the functions members of "buf"
or to overload operators (like iostream does).

woodb...@gmail.com

unread,
Nov 8, 2014, 4:17:14 PM11/8/14
to
I use "stuff taking things out of buf" approach if it's
a class. For example:

class cmw_request
{
marshalling_integer const accountNbr;
// ...

public:
template <class R>
explicit cmw_request (ReceiveBuffer<R>& buf) :
accountNbr(buf)
{}
};

I can't do that with primitive types since they
don't have constructors.

> Also chaining free functions
> looks ugly so either he has to make the functions members of "buf"
> or to overload operators (like iostream does).

For primitive types I've made the functions members
of buf.

Brian
Ebenezer Enterprises

woodb...@gmail.com

unread,
Nov 22, 2014, 4:33:17 PM11/22/14
to
Here are the details for the new offer:

We'll pay $1,400 and give a $1,200 investment in the company.
We'll pay the $1,400 after working for four months on the
project. The investment would result in between $0 and
$3,600, depending on how things go for the company. Tia

Mr Flibble

unread,
Nov 22, 2014, 5:18:02 PM11/22/14
to
Stop spamming the newsgroup with this nonsense Brian.

/Flibble

woodb...@gmail.com

unread,
Nov 22, 2014, 5:47:49 PM11/22/14
to
On Saturday, November 22, 2014 4:18:02 PM UTC-6, Mr Flibble wrote:
>
> Stop spamming the newsgroup with this nonsense Brian.
>

I claim the software is more robust and efficient than ever.

I'm afraid this is an example of one man's trash is
another man's treasure.

woodb...@gmail.com

unread,
Nov 29, 2014, 5:28:05 PM11/29/14
to

Currently all messages between my back and middle tiers
are compressed. The following shows the messages the
middle tier sends to the back tier.

middle_messages_back
@out (messageid_t, ::std::vector<cmw_account_info>)
@out (messageid_t, ::cmw::marshalling_integer, cui_generator)
@out (messageid_t)
}

The first message there is a login request. The second
is a code generation request and the last is a keep alive.
The keep alive is just a messageid_t which, in this case,
is one byte. After being compressed, the keep alive
message increases to 12 bytes. I think compression is
helpful for the code generation request message, but not
for the keep alive message. I'd guess compression isn't
helping with the login message either, but am not sure.
I've worked on systems that use compression for
everything or not at all. Have you ever worked on a
system that uses both compressed and non-compressed
messages? I'd like to find some info on systems like that.

Mr Flibble

unread,
Nov 29, 2014, 5:59:18 PM11/29/14
to
Sausages.

/Flibble

Ian Collins

unread,
Nov 29, 2014, 6:11:16 PM11/29/14
to
Compression is seldom any use for anything other than bulk transfer of
compressible data or sausages.

For inter-process or intra-process messages the overheads incurred by
compression tend to outweigh any benefits for short messages and for
LAN/WAN messaging packet latency has much more of a performance impact
than packet size.

One example is the application I use to distribute filesystems between
local and geographically distributed hosts, there I only consider
compression for full (not incremental) transfers of filesystems with a
worthwhile compress ratio.

--
Ian Collins

woodb...@gmail.com

unread,
Jan 8, 2015, 1:06:12 PM1/8/15
to
Below I've posted my front tier. It's only sixty some lines long.
It generates a request and uses UDP to send the request to the
middle tier. Then it waits for a reply. If it doesn't get a
reply, it generates another request and waits again.

One thing I've been thinking about is this line:

SendBuffer sendbuf(udp_packet_max);

That does a heap allocation of udp_packet_max bytes.
For the receive buffer I use the stack. I've thought
about changing the line above to be something like this:

::std::array<char, udp_packet_max> ar;
SendBufferStack(ar);

I've coded that, but haven't tested to see what the
performance is like. Anyway, I have some time to
work on these things and would like to get ideas on
how to improve this program or the rest of the code
and documentation on my site.

#include <platforms.hh>

#include <ErrorWords.hh>
#include <getaddrinfo_wrapper.hh>
#include <poll_wrapper.hh>
#include <ReceiveBufferUDP.hh>
#include <SendBuffer.hh>
#include <stdio.h>
#include <stdlib.h> // exit strtol
#include <syslog_wrapper.hh>
#include <udp_stuff.hh>
#include <zz.front_messages_middle.hh>

using namespace ::cmw;

int main (int argc,char** argv)
{
try{
if(argc<3 || argc>5){
printf("Usage: %s account-number config-file-path [node] [port]\n"
,argv[0]);
return EXIT_FAILURE;
}

#ifndef CMW_WINDOWS
::openlog(argv[0],LOG_NDELAY,LOG_USER);
#endif
windows_start();

getaddrinfo_wrapper res(3==argc ?"127.0.0.1":argv[3]
,argc<5 ?55555: ::strtol(argv[4],nullptr,10)
,SOCK_DGRAM);
SendBuffer sendbuf(udp_packet_max);
for(auto rp=res.get();rp!=nullptr;rp=rp->ai_next){
sendbuf.sock_=::socket(rp->ai_family,rp->ai_socktype,0);
if(-1==sendbuf.sock_)continue;

::pollfd fds {sendbuf.sock_,POLLIN,0};
int wait_millisecs=30000;
for(int jj=0;jj<2;++jj){
front_messages_middle::Marshal(sendbuf
,marshalling_integer(::strtol(argv[1],0,10))
,argv[2]);
sendbuf.Flush(rp->ai_addr,rp->ai_addrlen);
if(0==poll_wrapper(&fds,1,wait_millisecs)){
wait_millisecs*=2;
continue;
}

ReceiveBufferUDP<SameFormat> buf(fds.fd);
if(!buf.GiveBool())throw failure("CMWA: ")<<buf.GiveCharStar();
::exit(EXIT_SUCCESS);
}
}

throw failure("No reply received. Is the CMWA running?");
}catch(::std::exception const& ex){
::std::printf("%s: %s\n", argv[0],ex.what());
syslog_wrapper(LOG_ERR,"%s",ex.what());
return EXIT_FAILURE;
}
}



Brian
Ebenezer Enterprises - Thankful for France the country
who gave us the Statue of Liberty.

http://webEbenezer.net

Melzzzzz

unread,
Jan 8, 2015, 1:37:38 PM1/8/15
to
On Thu, 8 Jan 2015 10:05:56 -0800 (PST)
woodb...@gmail.com wrote:

> Below I've posted my front tier. It's only sixty some lines long.
> It generates a request and uses UDP to send the request to the
> middle tier. Then it waits for a reply. If it doesn't get a
> reply, it generates another request and waits again.
>
> One thing I've been thinking about is this line:
>
> SendBuffer sendbuf(udp_packet_max);
>
> That does a heap allocation of udp_packet_max bytes.
> For the receive buffer I use the stack. I've thought
> about changing the line above to be something like this:
>
> ::std::array<char, udp_packet_max> ar;
> SendBufferStack(ar);
>
> I've coded that, but haven't tested to see what the
> performance is like.

IO is much slower than any allocation. You wouldn't notice
any difference...

Jorgen Grahn

unread,
Jan 8, 2015, 3:44:57 PM1/8/15
to
There's not a lot of overhead for UDP ... I would measure before
saying anything for sure. (And perhaps before that, think about
whether it matters to my application.)

Melzzzzz

unread,
Jan 8, 2015, 4:25:45 PM1/8/15
to
On 8 Jan 2015 20:44:45 GMT
On average one cannot make more than 40k requests per second...

woodb...@gmail.com

unread,
Jan 25, 2015, 2:36:54 AM1/25/15
to

http://accu.org/index.php/conferences/accu_conference_2015/accu2015_sessions#just_keep_shipping

I like his title and agree with this:

"There is a customer expectation that the value of the product will improve over time without any effort on their part."

woodb...@gmail.com

unread,
Feb 5, 2015, 12:18:39 PM2/5/15
to
After reading in the recent "convert int to hex" thread,
I decided to remove the ::std from the line above. Now
it's just:

::printf("%s: %s\n", argv[0],ex.what());

I recall Alf S. arguing against using headers like cstdio.
I've been following that advice for a few years now without
any problems.


> syslog_wrapper(LOG_ERR,"%s",ex.what());
> return EXIT_FAILURE;
> }
> }
>
>

Brian

woodb...@gmail.com

unread,
Apr 2, 2015, 12:51:11 AM4/2/15
to
What do you think of this class?

class failure : public ::std::exception {
::std::string whatStr;

public:
explicit failure (char const* w) : whatStr(w) {}
explicit failure (::std::string w) : whatStr(::std::move(w)) {}

~failure () throw() {}

char const* what () const throw()
{ return whatStr.c_str(); }

failure& operator<< (char const* s)
{
whatStr.append(s);
return *this;
}

failure& operator<< (char* s)
{
whatStr.append(s);
return *this;
}

failure& operator<< (::std::string const& s)
{
whatStr.append(s);
return *this;
}

template <class T>
failure& operator<< (T val)
{
whatStr.append(::std::to_string(val));
return *this;
}
};

I'm thinking about changing it to something like this:

class failure : public ::std::string {

public:
explicit failure (char const* w) : std::string(w) {}
explicit failure (::std::string w) : std::string(::std::move(w)) {}

~failure () throw() {}

template <class T>
failure& operator<< (T val)
{
this->append(::std::to_string(val));
return *this;
}
};

Some preliminary tests show smaller executable sizes with
this second approach.

And there are *many* topics in this thread that I'd like
more thoughts on. Thanks in advance.

Brian
Ebenezer Enterprises - "The fear of the L-RD is the beginning
of wisdom, and knowledge of the Holy One is understanding."
Proverbs 9:10

http://webEbenezer.net

Daniel

unread,
Apr 2, 2015, 8:04:58 AM4/2/15
to
On Thursday, April 2, 2015 at 12:51:11 AM UTC-4, woodb...@gmail.com wrote:
> What do you think of this class?
>
> class failure : public ::std::exception {
> ::std::string whatStr;
>
> failure& operator<< (::std::string const& s)
> {
> whatStr.append(s);
> return *this;
> }
>

I think it's a bad idea to mutate an exception instance once thrown, rather, create new exception instances that preserve the old information and augment with new. You may wish to keep a chain of original and augmented exceptions, but in any case the exception should be immutable.

Daniel

Mr Flibble

unread,
Apr 2, 2015, 2:20:48 PM4/2/15
to
You should have rich exception types that relate to the actual
exceptional behaviour not a generic "failure" type which is little
better than throwing a std::string (and makes catching specific
exceptions harder).

/Flibble

Öö Tiib

unread,
Apr 3, 2015, 9:12:03 AM4/3/15
to
On Thursday, 2 April 2015 07:51:11 UTC+3, woodb...@gmail.com wrote:
> What do you think of this class?

Average class.

> class failure : public ::std::exception {
> ::std::string whatStr;
>
> public:
> explicit failure (char const* w) : whatStr(w) {}

Can use alternative syntax 'char const s[]' to indicate that C string
is expected.

> explicit failure (::std::string w) : whatStr(::std::move(w)) {}
>
> ~failure () throw() {}

Feels pointless to indicate 'noexcept' here since compiler can see it
itself. You can indicate that destructor is default and virtual like:

virtual ~failure() = default;

However since you do not define neither assignments nor
copy-constructions of 'failure' it feels better to remove the
destructor as well by rule of zero.

> char const* what () const throw()
> { return whatStr.c_str(); }

Can indicate that member function is virtual override (with keywords
'virtual' and 'override').

> failure& operator<< (char const* s)
> {
> whatStr.append(s);
> return *this;
> }
>
> failure& operator<< (char* s)
> {
> whatStr.append(s);
> return *this;
> }

That looks unneeded overload; its body is identical to previous overload.

> failure& operator<< (::std::string const& s)
> {
> whatStr.append(s);
> return *this;
> }
>
> template <class T>
> failure& operator<< (T val)
> {
> whatStr.append(::std::to_string(val));
> return *this;
> }

Can use:

using std::to_string;
whatStr.append(to_string(val));

That will consider likely 'to_string's from T's namespace in name lookup.

> };
>
> I'm thinking about changing it to something like this:
>
> class failure : public ::std::string {
>
> public:
> explicit failure (char const* w) : std::string(w) {}
> explicit failure (::std::string w) : std::string(::std::move(w)) {}
>
> ~failure () throw() {}
>
> template <class T>
> failure& operator<< (T val)
> {
> this->append(::std::to_string(val));
> return *this;
> }
> };
>
> Some preliminary tests show smaller executable sizes with
> this second approach.

Technically it is 'catch (std::string const&)' for user?

Performance considerations are always less important than usability
considerations so I usually derive exception types that may be
thrown out of my code from 'std::runtime_error'. Better usability
for caller, microscopic difference in performance.

If you really need such microscopic performance benefits then better
throw enwrapped into 'std::exception' string literals or integers.
IOW do not build long texts at throw site. For example: If catch
site can't do anything with long text that explains in detail what
strange byte sequence did not let a parser to parse the input,
then do not build such thing at throw site and executable size is
immediately smaller too.

woodb...@gmail.com

unread,
Apr 3, 2015, 9:20:39 PM4/3/15
to
On Friday, April 3, 2015 at 8:12:03 AM UTC-5, Öö Tiib wrote:
> On Thursday, 2 April 2015 07:51:11 UTC+3, woodb...@gmail.com wrote:
> > What do you think of this class?
>
> Average class.

Here's an updated version

class failure : public ::std::exception {
::std::string whatStr;

public:
explicit failure (char const* w) : whatStr(w) {}
explicit failure (::std::string w) : whatStr(::std::move(w)) {}

char const* what () const throw()
{ return whatStr.c_str(); }

failure& operator<< (char const* s)
{
whatStr.append(s);
return *this;
}

failure& operator<< (char* s)
{
whatStr.append(s);
return *this;
}

failure& operator<< (::std::string const& s)
{
whatStr.append(s);
return *this;
}

template <class T>
failure& operator<< (T val)
{
using ::std::to_string;
return *this << to_string(val);
}
};


I took your advice and removed the destructor and added
the using statement. I'm not sure what the advantage
would be to changing that signature from char const* to
char const [] so I didn't change that.


>
> > class failure : public ::std::exception {
> > ::std::string whatStr;
> >
> > public:
> > explicit failure (char const* w) : whatStr(w) {}
>
> Can use alternative syntax 'char const s[]' to indicate that C string
> is expected.
>
> > explicit failure (::std::string w) : whatStr(::std::move(w)) {}
> >
> > ~failure () throw() {}
>
> Feels pointless to indicate 'noexcept' here since compiler can see it
> itself.

I don't think of programs as selves. I'd compare a compiler
to a rock or a shovel.

>You can indicate that destructor is default and virtual like:
>
> virtual ~failure() = default;
>
> However since you do not define neither assignments nor
> copy-constructions of 'failure' it feels better to remove the
> destructor as well by rule of zero.
>
> > char const* what () const throw()
> > { return whatStr.c_str(); }
>
> Can indicate that member function is virtual override (with keywords
> 'virtual' and 'override').
>
> > failure& operator<< (char const* s)
> > {
> > whatStr.append(s);
> > return *this;
> > }
> >
> > failure& operator<< (char* s)
> > {
> > whatStr.append(s);
> > return *this;
> > }
>
> That looks unneeded overload; its body is identical to previous overload.
>

It looks that way to me too, but I've not been able to
get rid of it. If I remove it, the compiler chooses
between the char const* and the templated operator<<.
Rather than picking the char const* version, it picks
the templated version and then gives errors. Previously
on the newsgroup I mentioned this and someone suggested
using enable_if, but I wasn't crazy about that idea.
That seems to be easier said than done. I'm not sure who
does that.

Öö Tiib

unread,
Apr 4, 2015, 6:20:18 AM4/4/15
to
I wrote what I have seen some coding standards suggesting.
I am also not always sure about advantage, it is often just
syntax that some people consider easier to read, others not.

Sometimes there is practical value too. For example to
indicating 'override' consistently helps when someone changes
a base class virtual and forgets to update one of overrides.
It is then compile error since it does not override anything
anymore.

...

> I don't think of programs as selves. I'd compare a compiler
> to a rock or a shovel.

Software is more active than rock or shovel. It does sometimes rather
complex things on its own among other things. C++ code is text with
complex rules of interpretation so sometimes one may have to rearrange
it a bit to make it easier to parse for certain tools and people.

...

> > Technically it is 'catch (std::string const&)' for user?
> >
> > Performance considerations are always less important than usability
> > considerations so I usually derive exception types that may be
> > thrown out of my code from 'std::runtime_error'. Better usability
> > for caller, microscopic difference in performance.
> >
> > If you really need such microscopic performance benefits then better
> > throw enwrapped into 'std::exception' string literals or integers.
> > IOW do not build long texts at throw site. For example: If catch
> > site can't do anything with long text that explains in detail what
> > strange byte sequence did not let a parser to parse the input,
> > then do not build such thing at throw site and executable size is
> > immediately smaller too.
>
> That seems to be easier said than done. I'm not sure who
> does that.

What is 'that'? I would call your second version of 'failure' as
'string_builder'. It extended 'std::string' to make building
texts more convenient. That is why I suspected that may be you
build complex texts with it and maybe those texts are not really
useful.

We sometimes build complex texts for logging or tracing but it
is orthogonal to exceptions. Lot of logs and traces are only
temporary for debugging/testing and so removed or turned off
from end products but exceptions are functional part of behavior
and remain same.

Exceptions need to have sufficient variety of types so
catch site can catch 'my::FileNotFound', 'my::AccessDenied' and
'my::BadDataInFile' separately when there is difference in
handling or just 'std::exception' base class when there are
no difference in handling.

woodb...@gmail.com

unread,
Apr 28, 2015, 2:46:14 PM4/28/15
to
On Wednesday, April 1, 2015 at 11:51:11 PM UTC-5, woodb...@gmail.com wrote:
> What do you think of this class?
>
> class failure : public ::std::exception {
> ::std::string whatStr;
>
> public:
> explicit failure (char const* w) : whatStr(w) {}
> explicit failure (::std::string w) : whatStr(::std::move(w)) {}
>
> ~failure () throw() {}
>
> char const* what () const throw()
> { return whatStr.c_str(); }
>
> failure& operator<< (char const* s)
> {
> whatStr.append(s);
> return *this;
> }
>
> failure& operator<< (char* s)
> {
> whatStr.append(s);
> return *this;
> }
>
> failure& operator<< (::std::string const& s)
> {
> whatStr.append(s);
> return *this;
> }
>
> template <class T>
> failure& operator<< (T val)
> {
> whatStr.append(::std::to_string(val));
> return *this;
> }
> };
>

Often I use that class like this:

throw failure("poll failed: ") << errno;

So a std::string is constructed and then the errno in
string form is appended to the original string.

In a lot of cases, I have a good idea of how much more text
I'm going to append (potentially via multiple calls to
append) to the original string. So I was thinking it
would be helpful to have a std::string ctor that takes
both a char* and a value that indicates how many more
bytes to reserve beyond the length of the char*.

http://en.cppreference.com/w/cpp/string/basic_string/basic_string

It seems like that would help avoid some allocations and
moving of strings.

Öö Tiib

unread,
Apr 28, 2015, 3:58:38 PM4/28/15
to
Yes, but what good can the catch site do with that text?
Lot simpler to throw and easier to catch:

throw PollFailed( errno );

Catch site can differentiate between 'PollFailed' and
'ElectionFailed' by two catches and the errno is possible
to extract from 'PollFailed' (if interesting) without parsing
some sort of text. However if all of it it is anticipated
as uninteresting for catch site then why not just:

throw failure("");

???

Mr Flibble

unread,
Apr 28, 2015, 4:36:13 PM4/28/15
to
What the fuck are you doing mate? Exceptions should be thrown rarely not
routinely (mainly for exceptional conditions) so who cares about bloody
string allocations? I am sure you just think up random C++ shit to post
so you can advertise your bloody "middleware" project and your fucking god.

/Flibble

woodb...@gmail.com

unread,
Apr 28, 2015, 6:01:24 PM4/28/15
to
Leigh, please don't swear here.

I think most programs are servers now. After an exception is
thrown, there are more requests to handle. Those who care about
quality (e.g. robust and efficient exception handling) will care
about this.

Brian
Ebenezer Enterprises - "Everyone who drinks of this water will
thirst again; but whoever drinks of the water that I will give
him shall never thirst; but the water that I will give him will
become in him a well of water springing up to eternal life."
John 4:13 and 14

http://webEbenezer.net

Mr Flibble

unread,
Apr 28, 2015, 6:28:40 PM4/28/15
to
On 28/04/2015 23:01, woodb...@gmail.com wrote:
> Leigh, please don't swear here.

Why?

"That's 28 fucks. Including that one 29. Ah fuck it make it 30." -- Paul
Calf

>
> I think most programs are servers now. After an exception is
> thrown, there are more requests to handle. Those who care about
> quality (e.g. robust and efficient exception handling) will care
> about this.

Bullshit; it makes no difference if a program is a server or not:
exceptions should be thrown rarely not routinely so it matters little if
creating an exception object involves an extra string allocation.

>
> Brian
> Ebenezer Enterprises - "Everyone who drinks of this water will
> thirst again; but whoever drinks of the water that I will give
> him shall never thirst; but the water that I will give him will
> become in him a well of water springing up to eternal life."
> John 4:13 and 14

Evolution falsifies your bible, religion and god.

/Flibble

Drew Lawson

unread,
Apr 29, 2015, 12:45:52 PM4/29/15
to
In article <D9GdnRDo_MGucqLI...@giganews.com>
Mr Flibble <flibbleREM...@i42.co.uk> writes:

>What the fuck are you doing mate? Exceptions should be thrown rarely not
>routinely (mainly for exceptional conditions) so who cares about bloody
>string allocations?

I share that view, but not everyone does. A couple jobs back, I
was in an organization where exceptions were the preferred response
to almost everything. If a request was not a pure, unqualified,
success, the server threw an exception. Some parts would make a
request, catch the exception, change the request parameters, throw
a "try again" exception, catch that further up the stack, and then
resubmit the request.

Probably 1/4 of the application was try/catch blocks. Drove me
crazy, especially trying to find where in that flow to make an
otherwise simple change.


--
Drew Lawson | Radioactive cats have
| 18 half-lives
|

Chris Vine

unread,
Apr 29, 2015, 5:12:05 PM4/29/15
to
On Tue, 28 Apr 2015 15:01:11 -0700 (PDT)
woodb...@gmail.com wrote:
> Leigh, please don't swear here.

I wish you could get it into your somewhat curious system of reasoning
that "fuck" is not swearing. It is bad language (for some of the more
fastidious at least, personally I couldn't care a fuck).

Swearing is an offence to your god. Bad language is an offence to man.

Chris

Daniel

unread,
Apr 30, 2015, 7:25:44 AM4/30/15
to
On Wednesday, April 29, 2015 at 5:12:05 PM UTC-4, Chris Vine wrote:
> On Tue, 28 Apr 2015 15:01:11 -0700 (PDT)
> woodb...@gmail.com wrote:
> > Leigh, please don't swear here.
>
> I wish you could get it into your somewhat curious system of reasoning
> that "fuck" is not swearing.

Where I grew up, it was used as punctuation.

Daniel

woodb...@gmail.com

unread,
Apr 30, 2015, 2:38:35 PM4/30/15
to
On Tuesday, April 28, 2015 at 1:46:14 PM UTC-5, woodb...@gmail.com wrote:
>
> Often I use that class like this:
>
> throw failure("poll failed: ") << errno;
>
> So a std::string is constructed and then the errno in
> string form is appended to the original string.
>
> In a lot of cases, I have a good idea of how much more text
> I'm going to append (potentially via multiple calls to
> append) to the original string. So I was thinking it
> would be helpful to have a std::string ctor that takes
> both a char* and a value that indicates how many more
> bytes to reserve beyond the length of the char*.
>
> http://en.cppreference.com/w/cpp/string/basic_string/basic_string
>
> It seems like that would help avoid some allocations and
> moving of strings.
>

I've done some performance testing now comparing my original ctor:

explicit failure (char const* w) : whatStr(w) {}

with this one:

explicit failure (char const* w, int tot) {
if (tot > 0) whatStr.reserve(tot);
whatStr= w;
}

I used a test program like this:

#include "ErrorWords.hh"

void throws ()
{
throw cmw::failure("In the beginning was the Word.", 41) << 33 << " abcdefg";
}

int main ()
{
int p = 0;
for (int i = 0; i < 100000; ++i)
{
try {
throws();
} catch (std::exception const& ex){
++p;
}
}
printf("p is %d\n", p);
return 1;
}

--------------------------------------------------

The original version was about 20% slower than the newer
version on PC-BSD 10.1 and clang 3.4.1. I believe the new
ctor that I proposed could do a little better than the version
that first reserves and then copy-assigns the string. And it
would be easier to use as you wouldn't have to count/include
the length of the original text that you pass to the ctor.

I hope this ctor will be added to C++ 2015.


Brian
Ebenezer Enterprises - "What do you have that you have not received?"
1st Corinthians 4:7

http://webEbenezer.net

woodb...@gmail.com

unread,
Apr 30, 2015, 2:41:33 PM4/30/15
to
On Thursday, April 30, 2015 at 6:25:44 AM UTC-5, Daniel wrote:
>
> Where I grew up, it was used as punctuation.
>

I'm sorry to hear that.

Dombo

unread,
Apr 30, 2015, 2:42:47 PM4/30/15
to
Op 29-Apr-15 23:11, Chris Vine schreef:
Fuck god then.

Ian Collins

unread,
Apr 30, 2015, 3:16:10 PM4/30/15
to
I think you are missing the point - throwing an exception is an
exceptional event and the cost of constructing an exception object is
seldom a concern given all of the other overheads involved.

--
Ian Collins

woodb...@gmail.com

unread,
May 1, 2015, 12:00:19 PM5/1/15
to
On Thursday, April 30, 2015 at 2:16:10 PM UTC-5, Ian Collins wrote:
>
> I think you are missing the point - throwing an exception is an
> exceptional event and the cost of constructing an exception object is
> seldom a concern given all of the other overheads involved.
>

I think a ctor like that is useful beyond exception handling.

Rather than reserving enough space for the whole string and
then assigning the first part of the string, let the ctor
figure out how long the first part is and you only have to
tell it how much additional space to allocate.


Brian
Ebenezer Enterprises - G-d loves you.
http://webEbenezer.net


woodb...@gmail.com

unread,
May 1, 2015, 12:28:30 PM5/1/15
to
On Friday, May 1, 2015 at 11:00:19 AM UTC-5, woodb...@gmail.com wrote:
>
> I think a ctor like that is useful beyond exception handling.
>
> Rather than reserving enough space for the whole string and
> then assigning the first part of the string, let the ctor
> figure out how long the first part is and you only have to
> tell it how much additional space to allocate.
>

A ctor that takes two "char const*" would also be helpful
for reasons similar to those I mentioned previously.

Brian
Ebenezer Enterprises
http://webEbenezer.net

woodb...@gmail.com

unread,
May 3, 2015, 12:20:57 AM5/3/15
to
http://www.dailymail.co.uk/sciencetech/article-3064915/Is-internet-brink-collapse-web-reach-limit-just-eight-years-warn-engineers.html

The article says,

"Storing information in large 'server farms', rather than
transferring it, would take the strain off the network."

This is the approach I've taken with the C++ Middleware Writer --
files are only copied across the network if they have been updated.
I did this more to reduce bandwidth costs than thinking the
internet was unstable. I hope this article will encourage people
to consider their bandwidth consumption.

Scott Lurndal

unread,
May 3, 2015, 11:30:24 AM5/3/15
to
woodb...@gmail.com writes:
>http://www.dailymail.co.uk/sciencetech/article-3064915/Is-internet-brink-collapse-web-reach-limit-just-eight-years-warn-engineers.html
>
>The article says,
>
>"Storing information in large 'server farms', rather than
>transferring it, would take the strain off the network."
>
> I hope this article will encourage people
>to consider their bandwidth consumption.

I would hope that article teaches people to be less
gullible. The _Daily Mail_? Give me a break.

>
>Brian
>Ebenezer Enterprises - In G-d we trust.

Never mind, too late.

woodb...@gmail.com

unread,
May 13, 2015, 1:05:37 PM5/13/15
to
On Thursday, October 9, 2014 at 2:52:50 AM UTC-5, Jorgen Grahn wrote:
> On Tue, 2014-10-07, 嘱 Tiib wrote:
> > On Tuesday, 7 October 2014 21:58:34 UTC+3, woodb...@gmail.com wrote:
> ...
>
> > However 'cmw_account_info'? It is such
> > average name, only half of it is meaningless bloat and nothing
> > is misleading. Tolerable.
>
> I sometimes use the word "info" myself in variable and type names, but
> it's a small warning flag. E.g. is there a difference between a CMW
> Account object and the object carrying /info/ about a CMW Account?
>

I thought about it for a while and have now removed the
word "info" from that type. And getting back further in
the thread, I removed the check that the account number
supplied by the user is logged in. Specifically, I
removed it from my middle tier. There's still a check
in the back tier. Originally I added the check to
the middle tier to avoid some network traffic, but
decided after reading a post on Stackoverflow about
std::vector::at() that I could do without the extra
check. Anticipating sober-minded users, I think the
percentage of requests with the correct account number
will increase over time and eventually exceed 99.9%.

> More direct wording is better; it helps you think.
>

Brian
Ebenezer Enterprises - In G-d we trust.
http://webEbenezer.net

woodb...@gmail.com

unread,
Jun 10, 2015, 4:57:15 PM6/10/15
to
Here's an updated version of my front tier. One change
is I've moved the call to ::openlog into the catch block.
Mostly I work on servers and in servers I call openlog as
part of the non-error flow code. I think that's why I was
doing that in this code, but this isn't really a server so
decided to move that call into the catch block.

#include "ErrorWords.hh"
#include "getaddrinfo_wrapper.hh"
#include "poll_wrapper.hh"
#include "ReceiveBufferStack.hh"
#include "SendBufferStack.hh"
#include <stdio.h>
#include <stdlib.h> // exit
#include "syslog_wrapper.hh"
#include "zz.front_messages_middle.hh"

using namespace ::cmw;

int main (int argc,char** argv)
{
try{
if(argc<3 || argc>5)
throw failure("Usage: direct account-number .req-file-path [node] [port]");

windows_start();
getaddrinfo_wrapper res(3==argc?"::1"/*"127.0.0.1"*/:argv[3]
,argc<5?"55555":argv[4],SOCK_DGRAM);
auto rp=res.get();
SendBufferStack<> sendbuf;
for(;rp!=nullptr;rp=rp->ai_next){
if((sendbuf.sock_=::socket(rp->ai_family,rp->ai_socktype,0))>0)break;
}
if(-1==sendbuf.sock_)throw failure("socket call(s) failed ")<<GetError();

::pollfd pfd{sendbuf.sock_,POLLIN,0};
int waitMillisecs=30000;
for(int j=0;j<2;++j,waitMillisecs*=2){
front_messages_middle::Marshal(sendbuf,marshalling_integer(argv[1])
,argv[2]);
sendbuf.Flush(rp->ai_addr,rp->ai_addrlen);
if(poll_wrapper(&pfd,1,waitMillisecs)>0){
ReceiveBufferStack<SameFormat> buf(pfd.fd);
if(!buf.GiveBool())throw failure("CMWA: ")<<buf.GiveCharStar();
::exit(EXIT_SUCCESS);
}
}
throw failure("No reply received. Is the CMWA running?");
}catch(::std::exception const& ex){
::printf("%s: %s\n",argv[0],ex.what());
#ifndef CMW_WINDOWS
::openlog(argv[0],LOG_NDELAY,LOG_USER);
#endif
syslog_wrapper(LOG_ERR,"%s",ex.what());
return EXIT_FAILURE;
}
}


I've whittled this program down to 52 lines now. It's
meant to be the most portable of my 3 tiers.


Brian

Ebenezer Enterprises - Should Lena Dunham be publicly denounced,
removed from her job, and taken off air as Josh Duggar was?

http://webEbenezer.net

woodb...@gmail.com

unread,
Jun 24, 2015, 6:35:22 PM6/24/15
to

Greetings to Alf.

By the grace of G-d, I'm able to devote more time than ever now
to the C++ Middleware Writer. So your thoughts on topics in this
thread are appreciated.

I've been thinking about changing things in my middle tier.
Currently I use a file to store the time of the most recent
update to a group of files. When a request from the front
tier arrives, I take the following steps:

open a file
read from the file
lseek back to beginning of file
write to the file
close the file

The first two of those steps happen prior to forwarding
the request from the middle to the back tier. The last
three steps happen after the middle tier has received
the reply from the back tier.

I've thought about an optimization where I'd cache open
file descriptors in a container and then do a lookup on
the container. That would eliminate the need for all
but the first open and all the closes.

I'm not very big on IDE's, but the file I'm talking about
is a little analogous to a project file. It's kind of a
meta file though about the project file and not the
project file. So basically a change to the name of the
file I'm talking about would cause my middle tier to have
some dangling data. That's not too big of a deal. If the
server ran for a few weeks it might accumulate a little.

I don't think my middle tier would handle it very well if
you changed the name of the file from A to B and then back
to A. It could handle going from A to B, but I think it
would have a problem with going back to A. So while this
sort of change is tempting from an efficiency perspective,
I'm not sure if it's worth it. The approach I currently
have works fine if you want to do an A to B to A change.
Thoughts on this? Thanks in advance.

woodb...@gmail.com

unread,
Jul 2, 2015, 1:55:26 AM7/2/15
to
On Wednesday, June 24, 2015 at 5:35:22 PM UTC-5, woodb...@gmail.com wrote:
> Greetings to Alf.
>
> By the grace of G-d, I'm able to devote more time than ever now
> to the C++ Middleware Writer. So your thoughts on topics in this
> thread are appreciated.
>

I hope people will realize the C++ community needs the
C++ Middleware Writer just as we need the C++ community.

Öö Tiib

unread,
Jul 3, 2015, 5:59:01 PM7/3/15
to
On Thursday, 2 July 2015 08:55:26 UTC+3, woodb...@gmail.com wrote:
> On Wednesday, June 24, 2015 at 5:35:22 PM UTC-5, woodb...@gmail.com wrote:
> > Greetings to Alf.
> >
> > By the grace of G-d, I'm able to devote more time than ever now
> > to the C++ Middleware Writer. So your thoughts on topics in this
> > thread are appreciated.
> >
>
> I hope people will realize the C++ community needs the
> C++ Middleware Writer just as we need the C++ community.

I think you are OK and all ... but I do not even see what is the
significance of your data serialization/deserialization/transfer utility
compared to any other similar thing. It is code like any other piece
of code. None of pieces of code can compare with community of humans,
so I don't get what you are saying.

woodb...@gmail.com

unread,
Jul 23, 2015, 6:21:25 PM7/23/15
to
On Friday, July 3, 2015 at 4:59:01 PM UTC-5, Öö Tiib wrote:
> On Thursday, 2 July 2015 08:55:26 UTC+3, woodb...@gmail.com wrote:
> > On Wednesday, June 24, 2015 at 5:35:22 PM UTC-5, woodb...@gmail.com wrote:
> > > Greetings to Alf.
> > >
> > > By the grace of G-d, I'm able to devote more time than ever now
> > > to the C++ Middleware Writer. So your thoughts on topics in this
> > > thread are appreciated.
> > >
> >
> > I hope people will realize the C++ community needs the
> > C++ Middleware Writer just as we need the C++ community.
>
> I think you are OK and all ... but I do not even see what is the
> significance of your data serialization/deserialization/transfer utility
> compared to any other similar thing.

It's an on line alternative.

woodb...@gmail.com

unread,
Aug 10, 2015, 3:36:08 PM8/10/15
to

I guess the C++ Middleware Writer is the elephant in the
room. It's met with silence and denial by some, but we
continue working on the software and hardware.

I'm willing to donate 16 hours/week for six months to a
project that uses the C++ Middleware Writer.

Also I'll pay $1,400 and give a $1,200 investment in the
company to someone who helps us find someone interested in this.
I'll pay the $1,400 after working for four months on the project.
Ebenezer Enterprises works to reward investments to 3 times the
original amount. So the investment would result in between
$0 and $3,600, depending on how things go for the company.

Brian
Ebenezer Enterprises - In G-d we trust.
http://webEbenezer.net
~
~

woodb...@gmail.com

unread,
Aug 22, 2015, 11:18:51 PM8/22/15
to
On Monday, August 10, 2015 at 2:36:08 PM UTC-5, woodb...@gmail.com wrote:
> I guess the C++ Middleware Writer is the elephant in the
> room. It's met with silence and denial by some, but we
> continue working on the software and hardware.
>

Horton Hears a Who.


> I'm willing to donate 16 hours/week for six months to a
> project that uses the C++ Middleware Writer.
>
> Also I'll pay $1,400 and give a $1,200 investment in the
> company to someone who helps us find someone interested in this.
> I'll pay the $1,400 after working for four months on the project.
> Ebenezer Enterprises works to reward investments to 3 times the
> original amount. So the investment would result in between
> $0 and $3,600, depending on how things go for the company.
>

Brian
Ebenezer Enterprises - A person's a person no matter how small.
http://webEbenezer.net

woodb...@gmail.com

unread,
Sep 13, 2015, 8:47:08 AM9/13/15
to
I've been thinking about servers lately. From what I can
tell hardware servers are primarily used to run multiple
instances of a single process. These are "dedicated"
servers. I'm wondering about another context where a
variety of software servers run on a hardware server.
I think my back tier (CMW) is an example of the former
and my middle tier (CMW Ambassador) is an example of the
latter. Is there research or terminology to describe
the latter context -- maybe a "mixed" or "hetereogenous"
server? Tia.

Brian
Ebenezer Enterprises - In G-d we trust.
http://webEbenezer.net




Ian Collins

unread,
Sep 13, 2015, 5:52:11 PM9/13/15
to
woodb...@gmail.com wrote:
> I've been thinking about servers lately. From what I can
> tell hardware servers are primarily used to run multiple
> instances of a single process.

Hardware servers are primarily used to run virtualised servers these days.

> These are "dedicated"
> servers. I'm wondering about another context where a
> variety of software servers run on a hardware server.
> I think my back tier (CMW) is an example of the former
> and my middle tier (CMW Ambassador) is an example of the
> latter. Is there research or terminology to describe
> the latter context -- maybe a "mixed" or "hetereogenous"
> server? Tia.

There isn't really a distinction. Some applications are flexible enough
to run components over multiple hosts, other are not. So the use case
is application, not server, driven.

--
Ian Collins

woodb...@gmail.com

unread,
Oct 25, 2015, 1:06:05 PM10/25/15
to

"YMMV, but I would stop worrying about supporting all container
types: You need only exactly four containers: vector<>,
unordered_map<>, deque<>, and unordered_set<> in this order.
Of these, only the vector<> is the general work-horse, the
others are only useful in special situations. Most importantly,
you should never use a list<> or forward_list<>, these can be
replaced by a vector<> in all cases, and the vector<> will be
significantly faster. That is, well over 90% of your containers
should be vector<>, and the special cases are, well, special
anyway."


That's from a comment to a question on Stackoverflow.
Are there some cases where std::list::splice makes list a
good choice?

I'm wondering whether to keep supporting std::list and
slist in the C++ Middleware Writer. Should std::list
be deprecated?

Jorgen Grahn

unread,
Oct 25, 2015, 1:58:08 PM10/25/15
to
On Sun, 2015-10-25, woodb...@gmail.com wrote:
>
> "YMMV, but I would stop worrying about supporting all container
> types: You need only exactly four containers: vector<>,
> unordered_map<>, deque<>, and unordered_set<> in this order.
> Of these, only the vector<> is the general work-horse, the
> others are only useful in special situations. Most importantly,
> you should never use a list<> or forward_list<>, these can be
> replaced by a vector<> in all cases, and the vector<> will be
> significantly faster. That is, well over 90% of your containers
> should be vector<>, and the special cases are, well, special
> anyway."
>
>
> That's from a comment to a question on Stackoverflow.

Without seeing that question, it's impossible to comment on it.
What does "support" refer to?

It's true that std::vector is the container that should see the most
use, but labeling the others as "special cases" is not helpful. I also
don't see why you'd want to stick to a subset of four containers.
They are there to be used, and it's not a horrible burden to
understand how to use one, once you know how to use another ...

> Are there some cases where std::list::splice makes list a
> good choice?
>
> I'm wondering whether to keep supporting std::list and
> slist in the C++ Middleware Writer. Should std::list
> be deprecated?

/Jorgen

--
// Jorgen Grahn <grahn@ Oo o. . .
\X/ snipabacken.se> O o .

Mr Flibble

unread,
Oct 25, 2015, 2:01:49 PM10/25/15
to
That StackOverflow comment is utter bollocks; I don't understand how
some people can get a good "reputation" on that site.

All the std containers are useful and have their specific complexity,
element reference/iteration invalidation and ordering requirements for
their various operations and controlled sequences. Some containers you
will tend to use more then others (e.g. std::vector) but that does not
mean the others are no good. Saying you shouldn't use std::list is
basically saying that you shouldn't use linked-list data structures
which is of course total nonsense.

/Flibble

woodb...@gmail.com

unread,
Oct 25, 2015, 2:23:44 PM10/25/15
to
On Sunday, October 25, 2015 at 12:58:08 PM UTC-5, Jorgen Grahn wrote:
> On Sun, 2015-10-25, woodb...@gmail.com wrote:
> >
> > "YMMV, but I would stop worrying about supporting all container
> > types: You need only exactly four containers: vector<>,
> > unordered_map<>, deque<>, and unordered_set<> in this order.
> > Of these, only the vector<> is the general work-horse, the
> > others are only useful in special situations. Most importantly,
> > you should never use a list<> or forward_list<>, these can be
> > replaced by a vector<> in all cases, and the vector<> will be
> > significantly faster. That is, well over 90% of your containers
> > should be vector<>, and the special cases are, well, special
> > anyway."
> >
> >
> > That's from a comment to a question on Stackoverflow.
>
> Without seeing that question, it's impossible to comment on it.
> What does "support" refer to?

I should have included the link in my post.

http://stackoverflow.com/questions/33329031/size-of-unknown-container

Jorgen Grahn

unread,
Oct 25, 2015, 3:25:10 PM10/25/15
to
Ok, thanks. I guess the relevant part of the question is

"What is the alternative to my_vector.size() that will work for
all containers including normal arrays?"

I /think/ what the response is trying to say is "don't worry so much
about supporting all possible container-like things with one piece of
code; you're likely to use it with only one or two containers".

But I'm not sure.

Chris Vine

unread,
Oct 27, 2015, 5:35:57 PM10/27/15
to
On Sun, 25 Oct 2015 10:05:42 -0700 (PDT)
woodb...@gmail.com wrote:
snip]
> That's from a comment to a question on Stackoverflow.
> Are there some cases where std::list::splice makes list a
> good choice?

Using std::list::splice for removing and inserting elements offers the
closest to lock-free performance you can get for a standard container
under contention from multiple threads. That is because it only swaps
pointers: you only need lock a mutex for the pointer swap, not for the
construction, destruction and copying of nodes. Depending on the
container element you may of course get better performance under
contention by using a truly lock-free solution, but that doesn't suit
all cases.

There might also be a case for using std::list where the container
element is not a built-in type, is large and does not have an efficient
move assignment operator, and you need both to have an ordered
container and to make many insertions and deletions throughout the
container. But you would need convincing evidence with profiling first.

Chris

Mr Flibble

unread,
Oct 27, 2015, 7:09:23 PM10/27/15
to
There are plenty of reasons for using std::list.

/Flibble

woodb...@gmail.com

unread,
Dec 20, 2015, 12:00:14 PM12/20/15
to
These days I only use std::list as a last resort.

woodb...@gmail.com

unread,
Dec 20, 2015, 12:07:45 PM12/20/15
to

Is there a growing appreciation for on line code generation
here? Economies around the world are declining so I think
this is helping to spur more interest. Here in the US we
have the 20-trillion-dollar man.

Daniel

unread,
Dec 20, 2015, 1:26:13 PM12/20/15
to
On Sunday, December 20, 2015 at 12:07:45 PM UTC-5, woodb...@gmail.com wrote:
> Is there a growing appreciation for on line code generation
> here?

We're all waiting on the excellent Mr Flibble, as soon as he gives
the word, we're all on board.

Daniel

Mr Flibble

unread,
Dec 20, 2015, 6:38:08 PM12/20/15
to
Brian's on-line code generator throws an exception if you present it
with sausages so it still needs work I'm afraid.

/Flibble

woodb...@gmail.com

unread,
Dec 20, 2015, 7:55:05 PM12/20/15
to
There's good reason to avoid bacon, ham and sausages -

http://www.bbc.com/news/health-34615621

"Its report said 50g of processed meat a day - less than two
slices of bacon - increased the chance of developing colorectal
cancer by 18%."

Brian
Ebenezer Enterprises -

"...That's what Christmas is all about, Charlie Brown."
https://www.youtube.com/watch?v=DKk9rv2hUfA

http://webEbenezer.net

woodb...@gmail.com

unread,
Jan 2, 2016, 8:59:38 PM1/2/16
to

http://stackoverflow.com/questions/34521354/tcp-ip-server-in-c-is-not-waiting-for-client/34539331#34539331

That thread says socket descriptors returned by accept()
can be negative. The documentation on FreeBSD and Linux
says accept() returns a non-negative number if successful.
Are there some systems where accept() can return negative
socket descriptors? Tia

Jorgen Grahn

unread,
Jan 3, 2016, 3:47:57 AM1/3/16
to
On Sun, 2016-01-03, woodb...@gmail.com wrote:
>
> http://stackoverflow.com/questions/34521354/tcp-ip-server-in-c-is-not-waiting-for-client/34539331#34539331
>
> That thread says socket descriptors returned by accept()
> can be negative.

Yes it does say that:

"Your error tests are invalid. It isn't correct to test for <
-1. A socket FD for example can have any value except -1. You
should test the result of every system call for == -1. 2. As
you're using Winsock, errno and friends don't work. Use
WSAGetLastError()"

> The documentation on FreeBSD and Linux says accept() returns a
> non-negative number if successful.

In Unix sockets are file descriptors, and those start at 0.

> Are there some systems where accept() can return negative socket
> descriptors?

Apparently Windows, according to that guy on stackoverflow. But why
they would create such a gratituous incompatibility with Unix, I don't
know -- not much point in implementing what looks a lot like the BSD
Sockets interface, and fail there. (Disclaimer: I have never done any
Windows programming.)

To get back to C++, Boost.Asio seems like a good way to write portable
code using TCP if you cannot assume POSIX.

Scott Lurndal

unread,
Jan 4, 2016, 10:13:23 AM1/4/16
to
Jorgen Grahn <grahn...@snipabacken.se> writes:
>On Sun, 2016-01-03, woodb...@gmail.com wrote:
>>
>> http://stackoverflow.com/questions/34521354/tcp-ip-server-in-c-is-not-waiting-for-client/34539331#34539331
>>
>> That thread says socket descriptors returned by accept()
>> can be negative.
>
>Yes it does say that:
>
> "Your error tests are invalid. It isn't correct to test for <
> -1. A socket FD for example can have any value except -1. You
> should test the result of every system call for == -1. 2. As
> you're using Winsock, errno and friends don't work. Use
> WSAGetLastError()"
>
>> The documentation on FreeBSD and Linux says accept() returns a
>> non-negative number if successful.

In general, if an interface says it returns -1 on error, then the only
correct way to code the test is to compare directly to -1; it is
not correct to consider any value less than zero to be an error.

lseek() was a classic example of this when used with SVR4 /proc. The
off_t argument (and return value) needed to be treated as unsigned to
allow the entire process address space to be accessed.

mmap() is another example, where the special value "MAP_FAILED" is defined
for applications to check the return value against.

Jorgen Grahn

unread,
Jan 4, 2016, 5:10:52 PM1/4/16
to
On Mon, 2016-01-04, Scott Lurndal wrote:
> Jorgen Grahn <grahn...@snipabacken.se> writes:
>>On Sun, 2016-01-03, woodb...@gmail.com wrote:
>>>
>>> http://stackoverflow.com/questions/34521354/tcp-ip-server-in-c-is-not-waiting-for-client/34539331#34539331
>>>
>>> That thread says socket descriptors returned by accept()
>>> can be negative.
>>
>>Yes it does say that:
>>
>> "Your error tests are invalid. It isn't correct to test for <
>> -1. A socket FD for example can have any value except -1. You
>> should test the result of every system call for == -1. 2. As
>> you're using Winsock, errno and friends don't work. Use
>> WSAGetLastError()"
>>
>>> The documentation on FreeBSD and Linux says accept() returns a
>>> non-negative number if successful.
>
> In general, if an interface says it returns -1 on error, then the only
> correct way to code the test is to compare directly to -1; it is
> not correct to consider any value less than zero to be an error.

Just for clarity (not to disagree) I'd like to point out again that
we're talking about /two different/ interfaces: Winsock and BSD
sockets.

woodb...@gmail.com

unread,
Jan 16, 2016, 8:42:40 AM1/16/16
to
A friend has given me hundreds of his technical books.
I've just started going through them. I've recycled
the books on Java, Python, Perl, Ruby, CSS and HTML. I'm not
looking at the books at them moment, but I would guess
there are at least 30 books about UML. The C++ books
are from Scott Meyers, Stroustrup, Koenig and others.
There are lots of books also on writing compilers.
I'm leaning toward recycling most of the UML books.

G-d willing, I'll post more about these books in the
future with more details. I'd like help in deciding
which books to recycle/give away and which to keep.

Alf P. Steinbach

unread,
Jan 16, 2016, 10:48:44 AM1/16/16
to
On 1/16/2016 2:42 PM, woodb...@gmail.com wrote:
> A friend has given me hundreds of his technical books.
> I've just started going through them. I've recycled
> the books on Java, Python, Perl, Ruby, CSS and HTML. I'm not
> looking at the books at them moment, but I would guess
> there are at least 30 books about UML. The C++ books
> are from Scott Meyers, Stroustrup, Koenig and others.
> There are lots of books also on writing compilers.
> I'm leaning toward recycling most of the UML books.
>
> G-d willing, I'll post more about these books in the
> future with more details. I'd like help in deciding
> which books to recycle/give away and which to keep.

I'd select one reference book on UML and ditch the rest of the UML books.

The aspects of notation that needs a deep long study simply aren't
useful, and engaging in such study is counter-productive.

Well unless you've paid some extortion-like licenses for some UML-based
"process" tool?


Cheers,

- Alf

Jorgen Grahn

unread,
Jan 16, 2016, 1:15:17 PM1/16/16
to
On Sat, 2016-01-16, Alf P. Steinbach wrote:
> On 1/16/2016 2:42 PM, woodb...@gmail.com wrote:
>> A friend has given me hundreds of his technical books.
>> I've just started going through them. I've recycled
>> the books on Java, Python, Perl, Ruby, CSS and HTML. I'm not
>> looking at the books at them moment, but I would guess
>> there are at least 30 books about UML. The C++ books
>> are from Scott Meyers, Stroustrup, Koenig and others.
>> There are lots of books also on writing compilers.
>> I'm leaning toward recycling most of the UML books.
>>
>> G-d willing, I'll post more about these books in the
>> future with more details. I'd like help in deciding
>> which books to recycle/give away and which to keep.
>
> I'd select one reference book on UML and ditch the rest of the UML books.
>
> The aspects of notation that needs a deep long study simply aren't
> useful,

Not unless everyone else knows the notation too, and IME people don't,
not in detail. I find class diagrams and state diagrams useful.
Others like the sequence diagrams, but it ends there. I haven't seen
the stick figures in a decade ...

woodb...@gmail.com

unread,
Jan 16, 2016, 4:26:11 PM1/16/16
to
On Saturday, January 16, 2016 at 9:48:44 AM UTC-6, Alf P. Steinbach wrote:
> On 1/16/2016 2:42 PM, woodb...@gmail.com wrote:
> > A friend has given me hundreds of his technical books.
> > I've just started going through them. I've recycled
> > the books on Java, Python, Perl, Ruby, CSS and HTML. I'm not
> > looking at the books at them moment, but I would guess
> > there are at least 30 books about UML. The C++ books
> > are from Scott Meyers, Stroustrup, Koenig and others.
> > There are lots of books also on writing compilers.
> > I'm leaning toward recycling most of the UML books.
> >
> > G-d willing, I'll post more about these books in the
> > future with more details. I'd like help in deciding
> > which books to recycle/give away and which to keep.
>
> I'd select one reference book on UML and ditch the rest of the UML books.
>

There aren't as many as I thought.

1. Elements of UML style by Ambler
2. UML 2.0 in a Nutshell
3. Advanced Object Oriented Analysis and Design using UML
4. Project Quality Assurance for UML-based Projects
5. UML Toolkit
6. Database Design for Smarties using UML
7. UML and C++: A Practical Guide to Object Oriented Development
8. UML 2.0 in Action
9. The UML Profile for Framework Architectures
10. Developing Software with UML
11. Real-time UML Second Edition by Douglass
12. UML Distilled Third Edition by Fowler
13. Applying UML and Patterns

There may be one or two more that I'm missing.

It looks like the 5th one, UML Toolkit, there's
been a "UML 2 Toolkit" published subsequently.
The book I have is probably kind of old. I agree
about keeping one or two at the most. Thanks.

It is loading more messages.
0 new messages