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

C or C++

152 views
Skip to first unread message

in...@meshparts.de

unread,
Jul 28, 2017, 2:00:31 AM7/28/17
to
Hi,

I'm planing to move some core functionality of my application from Tcl to C or C++. As always it's all about performance (speed and memory consumption) in processing large data structures (dict like) while using multi-threading.

The big question is: Which programming language should I use: C or C++?

I'm not a C/C++ programmer, so I have no decision base for this question.

I would love to hear the opinions of the Tcl community in this matter.

Many thanks!
Alexandru

rene

unread,
Jul 28, 2017, 4:13:36 AM7/28/17
to
Hi Alexandru

I would stick to plain C. Tcl/tk is at least just a simple C-library.
All interface functions are simple C-functions.
You could even use critcl to code your C-functions from tcl.
For more advanced use you can use the TEA system.

HTH
rene

Ralf Fassel

unread,
Jul 28, 2017, 4:25:22 AM7/28/17
to
* in...@meshparts.de
C++. Everything you can do in C, you can do in C++.
But in C++ you have the benefit of much easier memory handling, data
encapsulation by classes, platform independent threading in the recent
versions (C++14ff) if you're not using TCL's own, etc pp.

My €0.02
R'

rene

unread,
Jul 28, 2017, 5:43:31 AM7/28/17
to
Yes, C++ is more powerfull if you need it.
Otherwise if the power of C is enough you are more portable and see above :)

rene

in...@meshparts.de

unread,
Jul 28, 2017, 5:53:29 AM7/28/17
to
Thank you Rene and Ralf!
What about the API. Can I use the same Tcl/C API with C++?

rene

unread,
Jul 28, 2017, 7:28:47 AM7/28/17
to
Yes. It is just plain C-functions.

rene

EL

unread,
Jul 28, 2017, 8:25:55 AM7/28/17
to
Am Freitag, 28. Juli 2017 08:00:31 UTC+2 schrieb in...@meshparts.de:

> The big question is: Which programming language should I use: C or C++?

With respect to coding I would suggest C++. Its much easier to use and more powerful with its std lib, boost and templates. Effectively used you can reduce the code to a minimum and still have the speed and memory efficiency.

But with respect to portability I would suggest C. Its easier to handle with TEA and easier to compile for "exotic" platforms. For example you can compile a TEA compatible C extension into WebAssembly with almost no extra efford, but some features of C++ are not (yet) supported by WebAssembly (i.e. exceptions).

> I'm not a C/C++ programmer, so I have no decision base for this question.

You could also use another interresting approach: develop the extension in Rust, compile to a DLL/SO and expose a standard C ABI. As I understand from the docs, this is very easy in Rust. Then hook up the C functions to Tcl via Ffidl (https://github.com/prs-de/ffidl). It seems a bit cumbersome at a first glance, but is should be easy... and Rust is a much more interresting language than C++, imho :). Of course you can also create a DLL in C or C(++) and hook that up via Ffidl.
There are two interresting aspects with Ffidl: 1. it saves you from messing around with the Tcl C API. 2. you can use that DLL from anywhere and any language. Most dynamic languages support libffi in some way, and others have even easier interfacing capabilities to DLLs.

--
EL

Christian Gollwitzer

unread,
Jul 28, 2017, 5:38:41 PM7/28/17
to
Am 28.07.17 um 08:00 schrieb in...@meshparts.de:> I'm planing to move
some core functionality of my application from
> Tcl to C or C++. As always it's all about performance (speed and
> memory consumption) in processing large data structures (dict like)
> while using multi-threading.
>
> The big question is: Which programming language should I use: C or
> C++?


C++ is a almost a superset of C, so you can do everything in C++ what
can be done in C, and much more in addition. C++ is more expressive than
C and facilitates some tasks which are quite tedious in pure C, like
memory management (RAII idiom in C++) or error handling (exceptions).
There is also usually no performance penalty in number crunching tasks,
because C++ is made in a way that many of the nice features can be
statically compiled. Personally, if I'm allowed to choose, I'd always
use C++.

The Tcl community has traditinonally liked C more than C++, and Tcl
itself is written in C. There is one selling point of C: it is easier to
install / deploy software compiled in C. For some time in the past, this
was quite severe. Both C and C++ programs require runtime libraries
installed in the system in order to run, and the C library is usually
always installed, because the whole OS relies on it, whereas the C++
libraries were not always installed, and every compiler has had a
different version. For example, if you use Visual Studio, there is a
matching "Redistributable" from MS which you must install on the
computer along with your software. Today, it is rarely an issue, because
often the users already have these libraries from a different issues,
the newest versions of Visual Studio can use a library which comes with
Windows Update and generally it is not a big problem to include that
Redistributable package with your installer.

As an example of the capabilities of C++, consider the case where you
want to return a mixed dictionary from your code, like

{ Hello 3 Nested {a 5 b 6} }

where the numbers should be true IntObjs and the keys are strings.

If you know the Tcl C API, then it is a matter of creating the right
Tcl_Obj, Tcl_DictObjPut, taking care of the references and so. In case
you find an error in the middle of constructing the dict, you have to
make sure that everything is deleted, what was constructed, and nothing
more etc. So much more error checking, Tcl_DecrRefCount and so on. If
you have C++, you can write a generic wrapper like this:

https://pastebin.com/FJk934jR

This <500 LOC snippet contains an implementation for Tcl and Python to
construct mixed lists / dicts in conjunction with SWIG. A function
returning the structure above would look like this:

SWDict myfunc() {
SWDict result;
result.insert("Hello", 3);

SWDict nested;
nested.insert("a", 5);
nested.insert("b", 6);

result.insert("Nested", nested);
return result;
}

This takes automatically care of constructing the correct Tcl_Obj*,
dealing with the reference counting, if it fails halfway, by throwing an
exception, the memory will be released automatically. With a little more
effort, one could construct operators etc. to also work on these values.

Christian

in...@meshparts.de

unread,
Jul 29, 2017, 5:04:58 AM7/29/17
to
Thanks Christian for the detailed answer.
Indeed, the constructor function is very elegant.
But the wrapper with 500 LOC is somehow long (and perhaps slow?) if you only want to return a Tcl list, isn't it?
Second question: Is it possible to write the same wrapper in C? Then the constructor function would look similarly elegant?

Christian Gollwitzer

unread,
Jul 29, 2017, 4:01:38 PM7/29/17
to
Am 29.07.17 um 11:04 schrieb in...@meshparts.de:
> Am Freitag, 28. Juli 2017 23:38:41 UTC+2 schrieb Christian
> Gollwitzer:
>> If you have C++, you can write a
>> generic wrapper like this:
>>
>> https://pastebin.com/FJk934jR
>>
>
> Thanks Christian for the detailed answer. Indeed, the constructor
> function is very elegant. But the wrapper with 500 LOC is somehow
> long (and perhaps slow?)

No, the wrapper is not slow. It will compile down to the same code as if
you had used the Tcl C API directly. Each SWDict or SWList only holds
one Tcl_Obj*, and in C++, for some cases like this, there is no other
storage. The functionality of this wrapper is resolved at compile time,
it does not impose any runtime cost.

> if you only want to return a Tcl list, isn't
> it? Second question: Is it possible to write the same wrapper in C?

This wrapper uses a bunch of tricks (templates, overloads, destructor
and copy semantics) that are impossible in C. BTW that was just a sketch
that I used in some internal extension. For sure it can be done much
better and more complete by a master of C++. There does exist such a
thing for Python, it's called Boost::Python.

Back to my wrapper, if you do

SWList l;
l.push_back(3);
l.push_back(2.7);
l.push_back("Hello");


it will construct a TclWideIntObj, a TclDoubleObj and a TclStringObj and
append it. The compiler decides that based on the given type. Impossible
in C.

> Then the constructor function would look similarly elegant?

C does not have any constructor functions. The direct Tcl C API is the
best what you can get, and you know how it looks like:

Tcl_Obj * l = Tcl_NewObj();
Tcl_ListObjAppendElement(NULL, l, Tcl_NewWideIntObj(3));
Tcl_ListObjAppendElement(NULL, l, Tcl_NewDoubleObj(2.7));
Tcl_ListObjAppendElement(NULL, l, Tcl_NewStringObj("Hello", -1));


The wrapper - if done properly - compiles to the exact same code.

Now consider that you append something with a function that can fail.

C++:
============
l.push_back(failing_int_func());
=============
In C++, a function can throw an exception, analogously to Tcl where an
error can be thrown. This will abort the insertion, and also abort the
whole function and by virtue of the destructors, call Tcl_DecrRef on all
objects which have been constructed so far and free them.

C:
==============
int result;
int code = failing_int_func(&result);
if (code != TCL_OK) goto error1;

Tcl_ListObjAppendElement(interp, l, Tcl_NewWideIntObj(l));

...

return TCL_OK;

error1:
Tcl_DecrRefCount(l);
return TCL_ERROR;
==============

You have to do all that manually.
Consider multiple parts which could fail, you have to keep all the
destruction in the error goto label in the correct sequence and in sync
.... The C++ compiler basically transforms the single line into the mess
that you see in the C version.

For simpler cases, like accepting / returning a single scalar value,
there exist programs which write all that interface code for you. One is
critcl, another one is SWIG. SWIG is way more powerful, because it
understands C++ (it reads the code) and allows you to introduce new
types. For example. in photoresize I enhanced SWIG to work on Tk photo
images. Critcl is useful for simple cases (short functions, scalar
values) and it knows how to drive the compiler.


Christian

in...@meshparts.de

unread,
Jul 30, 2017, 5:51:05 AM7/30/17
to
Thanks, looks very promising and convincing.
C++ should be the way to go.
0 new messages