Sharing some thoughts on programming languages and gui toolkits.

I tried the ruby script, it only takes 33 lines of code and looks super simple.
The interface doesn't look as pretty as gtk, although that might not matter.
 
Just as show-off a compiled dlang+tk toolkit program doing a fahrenheit convertor,
Code:
import tkd.tkdapplication;                               // Import Tkd.
import std.conv;

class MyTkdApplication : TkdApplication{     // Extend TkdApplication.
    Frame frame;
    Entry entry;
    Button button;
    Label label;
    Button exitButton;

    private void exitCommand(CommandArgs args){  // Create a callback.
        this.exit();                                                            // Exit the application.
    }

    private void buttonPressed(CommandArgs args){  // Create a callback.
        string fs=entry.getValue();
        float f=to!float(fs);
        float c=(f-32.0)*5.0/9.0;
        string cs=to!string(c);
        label.setText(cs);
    }

    override protected void initInterface(){             // Initialise user interface.
   
        frame = new Frame(2, ReliefStyle.groove)         // Create a frame.
            .pack(10);                                   // Place the frame.

        entry = new Entry(frame)   // Create a entry.
            .pack(10);                       // Place the entry.

        button = new Button(frame, "Convert ")   // Create a button.
            .setCommand(&this.buttonPressed)    // Use the callback.
            .pack(10);                                   // Place the button.

        label = new Label(frame, "____________")  // Create a label.
            .pack(10);                                   // Place the label.

        exitButton = new Button(frame, "Exit")    // Create a button.
            .setCommand(&this.exitCommand)    // Use the callback.
            .pack(10);                                   // Place the button.
    }
}

void main(string[] args){
    auto app = new MyTkdApplication(); // Create the application.
    app.run();                                           // Run the application.
}
 
The same in Tcl/Tk would look like this (done in 5 minutes):
Code:
#!/usr/local/bin/wish8.6

proc myresult {} {
    .f.r configure -text [ expr ([ .f.v get ] - 32.0) * 5.0 / 9.0 ]
}

frame  .f -relief groove -borderwidth 2 -pady 10 -padx 10
entry  .f.v
button .f.c -text "Convert" -command myresult
label  .f.r -text "____________"
button .f.q -text "Exit" -command exit
pack   .f.v .f.c .f.r .f.q -pady 10 -padx 10
pack   .f -pady 10 -padx 10
(Misses - like the "original" - input/error handling, window resizing, any aligns/expands for the widgets, infos for the window manager etc. - and uses the old style Tk toolkit… and maybe much more that should be done before it's a program for the people.)
 
Tk, an extension of tcl, was mentioned many times in conjunction with other scripting languages,
but you were the first mentioning tcl. Why?
I love Tcl (and Tk) for its simple, but powerfull and complete command syntax - just a few commands can do anything. It's rock solid since ever, platform independent since ever (even when it comes to file paths, accessing fonts etc.), and: still alive (!).

If you used and liked Tcl: No matter what you try later, compared to Tcl everything is kind of … half-hearted, cumbersome, contructed… just not up to scratch, leaves you with the feeling "hm, that's not the real thing"…

The only thing missing: A clever handling of multidimensional, associative arrays (the way like PHP offers); In Tcl you often use lists, which I don't really use in other programming languages anymore.

Much of my daily work environment and tools I wrote myself in Tcl (/Tk): Offering / invoicing / accounting software (Tcl/Tk is often named "just for small apps", but you can do real huge and complex stuff as well), programming environment (!), time tracking + calendar + todo list, a style engine for Garmin GPS devices (used for self made hiking maps), mass rename & time adjust (to merge more than one cameras photos/videos from a trip into one sorted directory), (un)mounting any storages/disk, get the weather forecast (into conky), my alterantive to a spreadsheets, backup tool (has to be as comfortable as possible, otherwise no enduser do backups), combine many PDFs into one via GUI, tea timer in system tray, battery status of my mouse as tray icon, wine cellar management, creating audio playlists for my DLNA server, view installed fonts, and even my website is dynamic driven by Tcl… Just to name a few of these tools ;)
 
I quite like Tk in terms of how its layout manager works.

However I wish there was a proper libtk library to use from C or C++. Being tied to Tcl means I can't use it for almost any of my projects. I would end up spending too long having to write bindings against all the other native middleware I use.
 
I do not think you must bind to all that. Tcl/tk C-API allow your C program to run tcl/tk scripts.
If you go that way round instead, those tcl/tk scripts will need to then call back into the C / C++ code (i.e on a button click). So you will end up indirectly having to make tcl bindings for your own software.

If you look around the internet, you will see that most tcl/tk documentation misses this part off "conveniently" because they know it is awkward.

The closest we have to a proper C++/tk binding is cpptk (http://cpptk.sourceforge.net/) but that has been unmaintained for years.
 
So you will end up indirectly having to make tcl bindings for your own software.
But I think it is no catastrophe.

There are two approachs: (1) C calls an interpreter that run tcl/tk code, some variables are exchanged between
C and the interpreter. (2) You extend tcl/tk with your C routines, and continue programming in tcl (main = tclsh main).
 
some variables are exchanged between
This is the tricky bit. Consider if you have to exchange an OpenSSL BIO or some composite type (like a struct). You can't pass those between language boundaries. If you try, you will need to describe the layout in both languages.
Also the difficulty is memory, if you hold onto a tcl object, you don't know the lifespan within the C or C++.

Likewise in C++ RAII might strip out the data (i.e when the std::shared_ptr<T> goes out of scope) so tcl is holding onto a dangling pointer.

Bindings are complex beasts. Bringing multiple languages into a project is non-trivial. Especially for something that is trivial like a GUI.
 
But the idea is to use tcl/tk only for bulding the GUI, for configuration scripts, mainly for interaction with the user.
Oh right. I tend to write GUI programs that need to do a little more than that. If it is just for simple configuration, then perhaps Zenity or CDialog is good enough.
 
I tend to write GUI programs that need to do a little more than that.
More than GUI is written in C with complex structures, the GUI in tcl/tk.

Or does "GUI programs" mean that the main functionality of the program is written in Xlib?!

And with configuration I also mean customization.

BTW. This was the original idea of tcl/tk. Later it began to be used as a scripting language to write
applications.
 
Or does "GUI programs" mean that the main functionality of the program is written in Xlib?!
Not necessarily Xlib but the main functionality of the program is often written entirely in C or C++.

The main bindings of Tk that are in common use are Perl (Perl/Tk) and Python (Tkinter). You will see with these you stick to Perl or Python for 100% of the program and you don't need to start injecting tcl scripts into the code and marshaling between data types.

These bindings are interesting because they are both done very differenty. Perl/Tk opted to directly bind against the underlying Tk C API which is very low level (actually lower level than Xlib). Whereas Tkinter instead uses tcl as an intermediate behind the scenes to tap into Tk. Both work quite effectively if your project doesn't depend on native C or C++.
 
The main bindings of Tk that are in common use are Perl (Perl/Tk) and Python (Tkinter).
And you can bind tcl/tk in your own applications: hence, main functionality in C.

As said, this was the now almost forgotten original idea of tcl that is perhaps alive in lua. I quote a well know
tcl textbook:

Tcl is implemented in a C library that is easy to integrate into an existing application. By adding the Tcl interpreter to your application, you can configure and control it with Tcl scripts, and with Tk you can provide a nice graphical interface to it. This was the original model for Tcl. Applications would be largely application-specific C code and include a small amount of Tcl for configuration and the graphical interface. However, the basic Tcl shells proved so useful by themselves that relatively few Tcl programmers need to worry about programming in C or C++.


The approach in the middle is to program critical things in C, extend tcl with that, and continue
programming in tcl.
 
And you can bind tcl/tk in your own applications: hence, main functionality in C.

As said, this was the now almost forgotten original idea of tcl that is perhaps alive in lua. I quote a well know
tcl textbook:




The approach in the middle is to program critical things in C, extend tcl with that, and continue
programming in tcl.
I really love that book. It enabled me in starting with Tcl very quick. At that time I have had to do a lot realted to automatic tests using signal generators, spectrum anaylsers and that kind of stuff. Tcl8.4 has been up to date and with the installation of the company ActiveState it was easy to start with, even on Windows.

The most fancy thing I have done in the past has been about audio processing. I hace used snack to get that data, FFTW for spectral analysis and some post processing for filtering and waterfall diagramms. The GUI and the things around have been Tcl/Tk code. I have interfaced snack, FFTW and some self written part for the waterfall stuff in C. For that your book has been extremly helpful. I am not a software engineer and even on C on a very low level. But with Tcl/Tk and your book this was possible for me.

Tcl/Tk might have an outdated image. But it is outstanding if it is about in making a tool with a GUI with very little effort in almost no time.
 
And you can bind tcl/tk in your own applications: hence, main functionality in C.
Heh yes but don't forget Perl and Python bindings have had teams spending decades on developing these bindings. It is too much for smaller projects.

Give it a shot and you will see what I mean. My prediction is that the code will be around 5x more than a standard C++ UI library. You will also lose most of the type safety.
 
Perl and Python bindings have had teams spending decades on developing these bindings. It is too much for smaller projects.
But they were not only making a widget for their programs, you have complete control of Tk in perl and python.

With extending I experimented a little and it is really easy, as chrbr noted. I cannot imagine that only
embedding is such a problem, I must try it more. But yes, since tcl evolved to a full scripting language,
the footprint may be bigger than a standard UI library. In C there is no much type safety to loss with a C library.
 
you have complete control of Tk in perl and python.
This is very much something I would like with C or C++. These bindings demonstrate that the market is there or they would not have gone through the effort of binding. Instead these communities could have just recommend using tcl from within Perl or Python directly.

In C there is no much type safety to loss with a C library.
So many other binding layers (i.e Java's JNI or Lua) present you with a void * which you need to do an unsafe cast to the correct type. This is certainly something I want to avoid. In large programs it is very difficult to keep track of with some pretty nasty results in terms of debugging time.

And with C++ a void * is useless, you can't put that in a std::shared_ptr<T> or you will end up with two separate ref counts that will always result in a double delete. You instead need a large amount of code to "discover" the original ref count container.
 
Instead these communities could have just recommend using tcl from within Perl or Python directly.
And then people would have begun using tcl instead of perl or python. It is really a joke that
tkinter needs to put the whole tcl/tk hidden in python for not programming GUIs directly with it,
but through python. A very good reason to use tcl instead of python.

In an extended tcl or in an application with embedded tcl one will use in any case tcl,
no need to disguise tcl/tk commands as commands in other language, as perl/python
need to do.

This is very much something I would like with C or C++.
Then you do not need a GUI, but a new widget toolkit?!

Tk has a problem: it does not support full unicode, you cannot represent arabic with diacritic signs
over the letters. I really have no much experience with GUI programming except with tk, I
programmed once a very simple program just for showing text with gtk, more simple is impossible:
it was very confuse and non natural.
So many other binding layers (i.e Java's JNI or Lua)

If you put there the whole tcl, for what do you need lua or java?! :)
 
. Consider if you have to exchange an OpenSSL BIO or some composite type (like a struct). You can't pass those between language boundaries. If you try, you will need to describe the layout in both languages.
BTW, if you insist on dealing with complex structures, see clientData here:


And for a concise introduction on extending tcl, see here:

 
Whilst it does look to have nicer FFI facilities than a lot of scripting layers, can you see here the unsafe cast (4th parameter)? https://github.com/flightaware/tclx/blob/master/doc/ObjCmdWrite.3#L396
Casting that back from ClientData is actually where the risk will come from.

The last parameter is also particularly awkward; that is the delete / finalizer function pointer. It will unfortunately work against C++ RAII and instead you will have to manually "pin" data to not be cleaned up. Even C middleware would be problematic because you don't always get to control the lifespan of things.

It just doesn't seem suitable for a number of use-cases. Possibly what has contributed towards a decline of Tk usage with C or C++. Of course these issues can all be worked around but it will be much more work than using a C or C++ toolkit.

For a little more info (because it is an interesting problem!), check out the Tcl Wiki page which also explains why embedding Tcl just to use Tk in a C++ application is not a good approach:

 
can you see here the unsafe cast (4th parameter)?

The last parameter is also particularly awkward; that is the delete / finalizer function pointer.
As far as I know, ClientData type is void*. And the pointer is passed to the function callback when the
function is called in a script. The finalizer is for treating client data on delete.

I have the impression that these kind of things are unavoidable in C and that you see it from a C++ perspective.

I have no idea of C++, and my C programs look like FORTRAN IV. What can I say?!

In any case, your quoted wiki page is interesting. But the thema there is embedding vs extending.
 
Back
Top