D

The D programming language is designed as an evolution of C/C++.

Documentation

Wikipedia
official wiki
old wiki
Feature Matrix

Tools

GDC
an open-source D compiler for GCC
LDC
an open-source D compiler based on LLVM
DMD
Official reference compiler, latest D version
Tkd
Tk toolkit for the D programming language v1.1.13 2019-06-13
tcltk
Tcl/Tk bindings for the D programming language v8.6.5 2015-03-31

See also

Example of a Tcl extension in D (D2)

Examples

Pat Thoyts' example (D1)

It is fairly simple to call Tcl from D. In fact, it looks a lot like C++ in most places. The main issue is to generate an import symbol file for the Tcl API, which can be done by using the genStubs script file.

Under Microsoft Windows I had to convert the standard ActiveTcl tcl83.lib to an OMF format library. To do this we convert to COFF format using Microsoft's LINK program and then Digital Mars' COFF2OMF utility

link /lib /convert tcl83.lib
coff2omd tcl83.lib

To illustrate, here is an initial stab. Build this using

dmd simple.d tcl83.lib  (Using Windows)

or

dmd simple.d -L-ltcl    (Using UNIX)
// simple.d - Copyright (C) 2003 Pat Thoyts <[email protected]>
//
// Demonstrate linking to Tcl from the D programming language. 
// See http://dlang.org/ for information
// about ``D''
//
// $Id: 6261,v 1.28 2006-11-20 19:00:16 jcw Exp $

import std.stream;
import std.string;
import std.compiler;

// ----------------------------------------------------------------------
// Define the bits we need for interfacing to Tcl API
//
extern (C) {
   alias void* ClientData;
   alias void (*Tcl_FreeProc)(char* blockPtr);
   alias void (*Tcl_CmdDeleteProc)(ClientData clientData);
   alias int (*Tcl_CmdProc)(ClientData clientData, Tcl_Interp* interp,
                            int argc, char* argv[]);
   alias void* Tcl_Command;

   struct Tcl_Interp {
      char* result;
      Tcl_FreeProc blockPtr;
      int errorLine;
   }

   enum {
      TCL_OK       = 0,
      TCL_ERROR    = 1,
      TCL_RETURN   = 2,
      TCL_BREAK    = 3,
      TCL_CONTINUE = 4,
   }

   const Tcl_FreeProc TCL_VOLATILE = cast(Tcl_FreeProc)1;
   const Tcl_FreeProc TCL_STATIC   = cast(Tcl_FreeProc)0;
   const Tcl_FreeProc TCL_DYNAMIC  = cast(Tcl_FreeProc)3;

   Tcl_Interp* Tcl_CreateInterp();
   Tcl_Command Tcl_CreateCommand(Tcl_Interp* interp, char* cmdName,
                                      Tcl_CmdProc proc,
                                 ClientData clientData,
                                 Tcl_CmdDeleteProc deleteProc);
   int   Tcl_Eval           (Tcl_Interp* interp, char* string);
   int   Tcl_EvalFile       (Tcl_Interp* interp, char* fileName);
   char* Tcl_GetStringResult(Tcl_Interp* interp);
   void  Tcl_SetResult      (Tcl_Interp* interp, char* str,
                              Tcl_FreeProc freeProc);
}

// ----------------------------------------------------------------------
int main(char[][] args)
{
   Tcl_Interp* interp = Tcl_CreateInterp();

   Tcl_CreateCommand(interp, "ddemo", &DDemoCmd,
                     null, null);

   int r;
   if( args.length < 2 )
   {
      r = Tcl_Eval(interp, "puts \"Tcl version: [info tcl]\"; ddemo");
   }
   else
   {
      r = Tcl_EvalFile(interp, args[1]);
   }
   printf(Tcl_GetStringResult(interp));
   return r;
}

// Add a new command to the Tcl interpreter.
// In this case: return some information about the D compiler.
extern (C):
int 
DDemoCmd(ClientData clientData, Tcl_Interp *interp, int argc, char* argv[])
{
   MemoryStream stm = new MemoryStream;
   stm.printf(std.compiler.name);
   stm.printf(" %d.%d", std.compiler.version_major, std.compiler.version_minor);
   Tcl_SetResult(interp, toStringz(stm.toString()), TCL_STATIC);
   return TCL_OK;
}

// ----------------------------------------------------------------------
//
// Local variables:
//   mode: c
//   compile-command: "dmd simple.d tcl83.lib"
//   cygwin: "gdc simple.d -ltcl"
// End:

nedbrek's example (D1)

nedbrek - I've updated the code for a later D compiler (cygming special, gdc 0.24, using dmd 1.020). You can then extract the Tcl declarations into a separate file (call it 'tcl.d'). To create an extension for Tcl, called 'test', put this in a file 'test.d':

import std.compiler;
import std.stream;
import std.string;
import std.c.windows.windows;
import tcl;

HINSTANCE g_hInst;

extern (C)
{
    void gc_init();
    void gc_term();
    void _moduleCtor();
}

extern (Windows)
BOOL DllMain(HINSTANCE hinst, ULONG reason, LPVOID rsvd)
{
    switch( reason )
    {
    case DLL_PROCESS_ATTACH:
        gc_init();
        _moduleCtor();
        break;
 
    case DLL_PROCESS_DETACH:
        gc_term();
        break;

    case DLL_THREAD_ATTACH:
    case DLL_THREAD_DETACH:
        return FALSE;
    }
    g_hInst = hinst;
 
    return TRUE;
}

extern (C)
int Test_Init(Tcl_Interp* interp)
{
    Tcl_CreateCommand(interp, "ddemo", &DDemoCmd, null, null);
    return TCL_OK;
}

extern (C)
int DDemoCmd(ClientData clientData, Tcl_Interp *interp, int argc, char* argv[])
{
    auto stm = new MemoryStream;
    stm.printf(std.compiler.name);
    stm.printf(" %d.%d", std.compiler.version_major,
               std.compiler.version_minor);
    Tcl_SetResult(interp, toStringz(stm.toString()), TCL_STATIC);
 
    return TCL_OK;
}

This can be built with:

gdc -shared -otest.so test.d -ltcl

It then works like a regular tcl extension:

$ tclsh
% load test.so
% ddemo

Discussion

SYStems: I would say C not used more because of competition, D is trying to compete a pretty saturated market.

  • For the open source croud, it will compete with C, C++, Java, possibly C# (mono and stuff)
  • For the commercial croud, it's mainly Java and C# and possibly C/C++
  • For somekind of croud, it's Haskell, OCaml, Scheme etc ...
  • For the looking for fun new languages to learn croud it's JavaScript (because of AJAX), Ruby, Perl 6 and Tcl 8.5 OO new features ;)

Those in my opinion are the market segments where D may compete and as I suggest they are saturated


As of October 2006, D is on the verge of being listed with Languages with a Tk binding

[L1 ].

RLH: That isn't how I read that thread.

LWV: After reading through the thread a bit, I see http://www.algonet.se/~afb/d/TK.zip is a beginning of a binding between D and Tk. Some of the issues are people wanting a D GUI that is designed with D philosophies, and later in the thread, concern about the fact that Tk requires X11 headers in some cases. I do not get the feeling that the D community itself is embracing Tk. Instead, there appears to be a number of people thinking about the possibility, with a larger number looking at alternatives.


Bindings to Tcl/Tk for the D programming language


July 2024: D's ImportC feature is good enough now that you don't need to generate bindings to use tcl.

All you need to do now is create a file called tcl.c and import it from D and it works like you would expect

I've only tested it with TCL9 beta.

//tcl.ct
#include <tcl.h>
//main.d
import tcl;
import std.stdio;


Tcl_Obj* tclString(string str)
{
        return Tcl_NewStringObj(str.ptr,str.length);
}

string dString(Tcl_Obj* str)
{
        long len;
        auto cstr = Tcl_GetStringFromObj(str,&len);
        return cast(string)cstr[0..len];
}

extern (C) int tcl_print(void* clientData,Tcl_Interp* interp,int objc,Tcl_Obj** objv)
{
        if (objc != 2) {
                return TCL_ERROR;
        }

        auto objs = objv[0..objc];

        writeln(objv[1].dString);
        Tcl_SetObjResult(interp,"Returned by D".tclString);

        return TCL_OK;
}

void main()
{
        auto interp = Tcl_CreateInterp();
        Tcl_CreateObjCommand(interp,"dprint",&tcl_print,null,null);
        Tcl_Eval(interp,"
                 puts [dprint {D param}];
                 puts {Hello World}"
        );
        Tcl_DeleteInterp(interp);
}
% ldc main.d tcl.c -L-ltcl9.0
% ./main
D param
Returned by D
Hello World