Jump to page: 1 2
Thread overview
A Programmer's Dilema: juggling with C, BetterC, D, Macros and Cross Compiling, etc.
Apr 30, 2023
Eric P626
Apr 30, 2023
Adam D Ruppe
Apr 30, 2023
Guillaume Piolat
May 01, 2023
Dukc
Apr 30, 2023
ryuukk_
May 01, 2023
PeeWee
May 01, 2023
Eric P626
May 01, 2023
Dukc
May 01, 2023
Mike Parker
May 02, 2023
Ali Çehreli
May 02, 2023
Eric P626
May 01, 2023
Mike Parker
May 01, 2023
Dadoum
May 06, 2023
Paolo Invernizzi
April 30, 2023

The title of this thread might be weird, but I am currently reconsidering the language and tools I am using before returning to production again.

Objective and projects

Make simple turn based (no animation) video games using Allegro 4, maybe 5, and eventually SDL on multiple platforms: Linux and Windows for now, but could expand, if possible, to other OS or hardware like MacOS, Android, Raspberry Pi, Arduino, etc. I will also be using Sqlite databases in most of my projects.

I have a set of projects I am decomposing and refactoring. I am wondering if I should continue in the same direction or if I should change my tools and languages. I am considering D or betterC as an alternative.

Language

I am currently using plain C and I love it. I am allergic to C++ and object oriented programming. Having read a bit about the features of the D language makes me doubt continuing using the C language. Especially the betterC option that allows making C compatible libraries and software using some of the D syntax. Unlocking for example the use of foreach statements.

The D syntax is interesting, trying to extend the C language the same way would require macros which is not recommended for many reasons. The C language evolves very slowly, so I'll probably be dead by the time they implements foreachs (bools are not even native to the language yet(requires stdbool.h). With D, I have 2 options: 1) create a D software with the D runtime 2) Create a betterC software that create C compatible code. I am making both games and libraries, so making C compatible libraries is almost essential.

The objective is to have a simple language, without object oriented stuff, that is relatively productive and allow low level manipulations. This explains the interest in getting foreachs for more control, security, less bugs therefore less debugging and more production.

So again betterC could be a good solution even though it's not well documented what features is exactly part of betterC. I wonder if it's worth learning the entire D language since a majority of the features might not make it to betterC. Also I have no interest in OOP, which is relatively present in the D language.

Cross-Compiling and Interoperability

This is where the troubles are starting. Now I am trying to figure out what can work together in a cross compiling context. Some of my projects are currently compiling windows binaries from linux OS using Mingw on gitlab.

Allegro seems to support both C and D, but if I only use the better C switch, I should be able to use any C library without any issue. Sqlite is also a plain C library, it should be usable with betterC and D.

But how is this possible in a cross-compiling context. I am not sure if I can do that with the D language either as pure D or better C. DMD does not seem to offer cross compiling. GDC can compile better C, but not sure mingw can compile D/betterC code.

So I am not really sure what can be done in cross-compiling, and if it works for Linux and Windows, it might not work for other platforms like MacOS, Rpie, Arduino if one day, I decide to take this route.

So what language do you recommend:

  • Keep everything in plain C
  • Use C patched with macros to gain some language features like Foreach
  • Use BetterC for everything
  • Use D for the games, and better C or C for the libraries(To keep some compatibilities)
  • Use D for everything, no C compatibility.

If you have other suggestions or questions let me know.

April 30, 2023

On Sunday, 30 April 2023 at 17:51:15 UTC, Eric P626 wrote:

>
  • Use D for everything, no C compatibility.

This is a false dilemma: D has full C compatibility.

April 30, 2023

On Sunday, 30 April 2023 at 17:51:15 UTC, Eric P626 wrote:

>

So what language do you recommend:

  • Keep everything in plain C
  • Use C patched with macros to gain some language features like Foreach
  • Use BetterC for everything
  • Use D for the games, and better C or C for the libraries(To keep some compatibilities)
  • Use D for everything, no C compatibility.

If you have other suggestions or questions let me know.

My recommendation would be to acclimate to D, use it with a C style, but do it in normal D (with bindbc bindings to C libraries like SDL or, considering where you are coming from, raylib). You could use BetterC for sure, but it's more practical in the long term to just learn to live with the GC: it is a one-time mental cost.

April 30, 2023

On Sunday, 30 April 2023 at 17:51:15 UTC, Eric P626 wrote:

>

The title of this thread might be weird, but I am currently reconsidering the language and tools I am using before returning to production again.

Objective and projects

Make simple turn based (no animation) video games using Allegro 4, maybe 5, and eventually SDL on multiple platforms: Linux and Windows for now, but could expand, if possible, to other OS or hardware like MacOS, Android, Raspberry Pi, Arduino, etc. I will also be using Sqlite databases in most of my projects.

I have a set of projects I am decomposing and refactoring. I am wondering if I should continue in the same direction or if I should change my tools and languages. I am considering D or betterC as an alternative.

Language

I am currently using plain C and I love it. I am allergic to C++ and object oriented programming. Having read a bit about the features of the D language makes me doubt continuing using the C language. Especially the betterC option that allows making C compatible libraries and software using some of the D syntax. Unlocking for example the use of foreach statements.

The D syntax is interesting, trying to extend the C language the same way would require macros which is not recommended for many reasons. The C language evolves very slowly, so I'll probably be dead by the time they implements foreachs (bools are not even native to the language yet(requires stdbool.h). With D, I have 2 options: 1) create a D software with the D runtime 2) Create a betterC software that create C compatible code. I am making both games and libraries, so making C compatible libraries is almost essential.

The objective is to have a simple language, without object oriented stuff, that is relatively productive and allow low level manipulations. This explains the interest in getting foreachs for more control, security, less bugs therefore less debugging and more production.

So again betterC could be a good solution even though it's not well documented what features is exactly part of betterC. I wonder if it's worth learning the entire D language since a majority of the features might not make it to betterC. Also I have no interest in OOP, which is relatively present in the D language.

Cross-Compiling and Interoperability

This is where the troubles are starting. Now I am trying to figure out what can work together in a cross compiling context. Some of my projects are currently compiling windows binaries from linux OS using Mingw on gitlab.

Allegro seems to support both C and D, but if I only use the better C switch, I should be able to use any C library without any issue. Sqlite is also a plain C library, it should be usable with betterC and D.

But how is this possible in a cross-compiling context. I am not sure if I can do that with the D language either as pure D or better C. DMD does not seem to offer cross compiling. GDC can compile better C, but not sure mingw can compile D/betterC code.

So I am not really sure what can be done in cross-compiling, and if it works for Linux and Windows, it might not work for other platforms like MacOS, Rpie, Arduino if one day, I decide to take this route.

So what language do you recommend:

  • Keep everything in plain C
  • Use C patched with macros to gain some language features like Foreach
  • Use BetterC for everything
  • Use D for the games, and better C or C for the libraries(To keep some compatibilities)
  • Use D for everything, no C compatibility.

If you have other suggestions or questions let me know.

I recommend using D with -betterC

D is better at being a better C than it is at being a better high level language

DMD doesn't support cross compilation but LDC do!

The consensus is to use DMD for fast compiles and then use LDC for your optimized release builds (LLVM is unmatched for optimizations, LDC is our savior)

So since you are making games, that's the perfect combo, and since game devs don't want any kind of GC or exception handling in their way, -betterC will suit your needs

-betterC and DMD is still painful to use for scenarios like this so be warned: https://issues.dlang.org/show_bug.cgi?id=20737, it is sad that it still is not fixed in 2023..

I suggest to maintain C compatibility since you are also making libraries, it would be sad for your users to not be able to consume your libs because it requires bunch of needs they do not use, C works everywhere and is one of the few languages that didn't got infested with OOP, screw redhat/gnome people

May 01, 2023
On Sunday, 30 April 2023 at 17:51:15 UTC, Eric P626 wrote:
>
> ....
> # Language
>
> I am currently using plain C and I love it. I am allergic to C++ and object oriented programming.
> ..

So... what can you do in C that you cannot do in C++ ??

C++ is essentially C .. plus.. you get 'selective' access to any and all the features of C++, should you ever decide some are actually useful in your projects.

C++ does not require you to think in terms of 'objects'. It just enables you to do so, if its helpful in your problem domain. It also enables you to just code in C, like you already do.

btw. Some of the worlds largest and most *successful* software projects are in fact... object oriented, not because its OOP, but because that style of programming was suitable in that particular problem domain.

Of course some of the worlds most successful software projects are written in pure C.

As much as I like D, I simply cannot say the same as above, for D -> yet.

I tried betterC a long...long time ago. The more I used it, the less I used it ;-)

Maybe things have changed.
May 01, 2023
> This is a false dilemma: D has full C compatibility.

From what I understand, D can use C, but C cannot use D? It's like C++: C++ can call C but C cannot call C++.

50% or more of my code will be put in re-usabled libraries. If I want people to use those libs, I would need to compile them in C or better C. Because betterC seems to create C libraries. If D can make C libraries, then indeed, I could do everything in D.

> You could use BetterC for sure, but it's more practical in the long term to just learn to live with the GC: it is a one-time mental cost.

I think I can live with the GC because it's not going to get called often in the end since I mostly use memory pre-allocation. You allocate everything on program start, and free it all on program's end. I am also not doing realtime games, so no possibility of lagging during animations.

The main issues seems portability and cross compiling.

> The consensus is to use DMD for fast compiles and then use LDC for your optimized release builds (LLVM is unmatched for optimizations, LDC is our savior)

Interesting, I found this page that seems to document it.

https://wiki.dlang.org/Cross-compiling_with_LDC

Lot of platforms seems available. Seems also compatible with Cmake which I am already using. I would need to make some build tests.

I'll have to see how Allegro, SDL and Sqlite can be integrated, one issue with cross compiling is that I need to have an library file compiled with Mingw for cross compiling and the regular lib for gcc building. If I could use the same lib for all platforms, that would be awesome.

> C++ is essentially C .. plus.. you get 'selective' access to any and all the features of C++, should you ever decide some are actually useful in your projects.

Sure, I could select a subset of the C++ language, and only benefit from those features. For example, I could have constructors for structs. But C++ is a language that tries to implement features the most convoluted way. You can end up with very complex error messages hard to analyze (very long variable types), hidden bugs hard to detect (ex: implicit function calls) and very complex syntax. So by restraining it to C, you remove all the possible crap that C++ can inject making it easier to program.

Sure if betterC has not much to offer, or if it's buggy, then maybe the choice will be between C and D. If LDC could indeed make cross-compiling easier that Mingw and Gcc, that would be a good reason to switch.

Is there a detailed list of the features you get in betterC?

I found this page that gives the list, but it's pretty vague:

https://dlang.org/spec/betterc.html

There is a make-over example here:

https://dlang.org/blog/category/betterc/

There is an interesting D for C programmers page

https://dlang.org/articles/ctod.html

But it seems to include more than the betterC features.

Now that you mention raylib ... it looks awesome. According to this cheatsheet:

https://www.raylib.com/cheatsheet/cheatsheet.html

It looks relatively accessible. Like Allegro, it's just a bunch of functions to call. It seems to support 3d polygons which I need for the maze engine, and have bitmap text support which I also need for the user interface. SDL did not have 3D polygons, and text support was limited. As for Allegro, I was stuck with the old Allegro 4 to get 3D polygons.

I makes me strongly consider switching library since Allegro 4 is old. Seems I have more research and testing to do.

... By the way, how do you change your avatar on this forum? There is no options on the settings page.
May 01, 2023

As others have said, you have no reason to restrict yourself to BetterC. If you dislike objects and/or other high-level features, you can simply use D in a low-level way like you'd use C. That works just as well from normal D as from BetterC. Both the C standard library and third-party C libraries are available in both cases.

And I do encourage that over time you gradually try the high-level features you don't have in C or even BetterC. It's likely you won't like all of them, and that's fine. For instance, it's pretty common for a D codebase to use object-oriented programming and exception only minimally or not at all. Still, almost certainly you will like something better than the C equivalent. For example, I've heard no-one preferring the concat function of C standard library over append operator (~) of a D string, except when it's necessary to do without the GC (and even then, A D programmer would likely devise something that works with slices and non-zero-terminated strings rather than concat).

On Sunday, 30 April 2023 at 18:15:31 UTC, Guillaume Piolat wrote:

>

You could use BetterC for sure, but it's more practical in the long term to just learn to live with the GC: it is a one-time mental cost.

Plus, even if you were to avoid the garbage collector, BetterC is not needed for that.

You want BetterC only if you want to avoid depending on DRuntime at all - maybe to write a library to be used from C or to write code to a platform without DRuntime port. And even in those cases, you have alternative ways to accomplish the same.

May 01, 2023

On Monday, 1 May 2023 at 09:17:14 UTC, Eric P626 wrote:

> >

This is a false dilemma: D has full C compatibility.

From what I understand, D can use C, but C cannot use D? It's like C++: C++ can call C but C cannot call C++.

50% or more of my code will be put in re-usabled libraries. If I want people to use those libs, I would need to compile them in C or better C. Because betterC seems to create C libraries. If D can make C libraries, then indeed, I could do everything in D.

D can make C libraries, BetterC or no.

The difference is that a vanilla D library has a DRuntime dependency, meaning the runtime has to be initialised. You can do that by either writing the main() function in D, or manually initialising the runtime from C before calling other D functions. Not sure of the specifics but I'm sure it's not too hard. Seems the C-linked functions in core.runtime ought to do the trick.

In BetterC, there is no DRuntime that needs initialising, but for a common application DRuntime is worth the hassle to initialise it many times.

May 01, 2023

On Monday, 1 May 2023 at 09:35:59 UTC, Dukc wrote:

>

hard. Seems the C-linked functions in core.runtime ought to do the trick.

If you're referring to rt_init and rt_term are the extern(C) functions in core.runtime. It's not necessary to call those from C. A D library with a C interface can provide an extern(C) initialization function that internally calls Runtime.initialize.

May 01, 2023

On Monday, 1 May 2023 at 09:17:14 UTC, Eric P626 wrote:

> >

This is a false dilemma: D has full C compatibility.

From what I understand, D can use C, but C cannot use D? It's like C++: C++ can call C but C cannot call C++.

>

50% or more of my code will be put in re-usabled libraries. If I want people to use those libs, I would need to compile them in C or better C. Because betterC seems to create C libraries. If D can make C libraries, then indeed, I could do everything in D.

D is ABI-compatible with C. BetterC has nothing to do with it. And if you're using BetterC just because you're linking with a C library, you're crippling your D code. That's not really a good use case for it.

Any D function marked as extern(C) can be called from C. As long as you have a C header file defining the functions and the appropriate C declarations any custom types you have, the C code will have no idea it's calling into a D library.

In your D library:

// This function can be called from C
extern(C) void functionForTheCAPI(const(char)* str) {
    import std.conv : to;
    doSomething(to!string(str));
}

// This is a D function that cannot be called from C
void doSomething(string s) { ... }

In the corresponding C header:

extern void functionForTheCAPI(const char* str);

Just #include the C header in your C code, link with the D library, and you're good to go. Make sure to include a function somewhere in your D library's C API to initialize DRuntime:

import core.runtime;

extern(C) int initialize() { return Runtime.initialize(); }

Add the declaration to a C header and you're good to go.

« First   ‹ Prev
1 2