www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - A Programmer's Dilema: juggling with C, BetterC, D, Macros and Cross

reply Eric P626 <ericp lariennalibrary.com> writes:
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.



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.



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.



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.
Apr 30 2023
next sibling parent Adam D Ruppe <destructionator gmail.com> writes:
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.
Apr 30 2023
prev sibling next sibling parent reply Guillaume Piolat <first.last spam.org> writes:
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.
Apr 30 2023
parent Dukc <ajieskola gmail.com> writes:
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
prev sibling next sibling parent ryuukk_ <ryuukk.dev gmail.com> writes:
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.



 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.



 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.



 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
Apr 30 2023
prev sibling next sibling parent reply PeeWee <PeeWee gmail.com> writes:
On Sunday, 30 April 2023 at 17:51:15 UTC, Eric P626 wrote:
 ....


 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.
Apr 30 2023
parent reply Eric P626 <ericp lariennalibrary.com> writes:
 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
next sibling parent reply Dukc <ajieskola gmail.com> writes:
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](https://dlang.org/phobos/core_runtime.html#.Runtime.initialize) 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
parent reply Mike Parker <aldacron gmail.com> writes:
On Monday, 1 May 2023 at 09:35:59 UTC, Dukc wrote:
 hard. Seems the C-linked functions in 
 [core.runtime](https://dlang.org/phobos/core_runtime.html#.Runtime.initialize)
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
parent reply =?UTF-8?Q?Ali_=c3=87ehreli?= <acehreli yahoo.com> writes:
On 5/1/23 03:23, Mike Parker wrote:

 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`.
Indeed. That appears at the following spot of one of my DConf presentations, which touches on several points relevant to writing a C library in D: https://youtu.be/FNL-CPX4EuM?t=2585 Ali
May 02 2023
parent Eric P626 <ericp lariennalibrary.com> writes:
 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.
Thanks for the example. It clarify things up. The druntime is just another dynamic library file I need to supply with my software. And I have interest in not statically linking it since the main program and the libraries will each need a copy of druntime. So it's more the cross-compiling that could remain an issue, but it does not seem that much more complex than it currently is with gcc and mingw. I guess I'll need to do some R&D for both D language and Raylib.
May 02 2023
prev sibling parent Mike Parker <aldacron gmail.com> writes:
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: ```D // 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: ```C 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: ```D import core.runtime; extern(C) int initialize() { return Runtime.initialize(); } ``` Add the declaration to a C header and you're good to go.
May 01 2023
prev sibling parent reply Dadoum <dadoum protonmail.com> writes:
On Sunday, 30 April 2023 at 17:51:15 UTC, Eric P626 wrote:
 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.
I build programs for macOS, iOS, Windows with ldc2 cross-compiling capabilities from my Linux computer, and the experience is okay, the executables are working fine but the set-up is a bit complicated, you need to copy files from the windows toolchain, copy your ldc config and edit it with some stuff, and do that at each ldc2 update. If you just need cross-architecture, then gdc is a good option since it is compiled in a lot of cross compilation toolchains. However, I never managed to build a working gdc myself with ucrt or mingw cross-compilation capabilities, it always ends up with a compiler unable to link or executables that can't be executed on Windows.
May 01 2023
parent Paolo Invernizzi <paolo.invernizzi gmail.com> writes:
On Monday, 1 May 2023 at 16:57:39 UTC, Dadoum wrote:
 On Sunday, 30 April 2023 at 17:51:15 UTC, Eric P626 wrote:
 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.
I build programs for macOS, iOS, Windows with ldc2 cross-compiling capabilities from my Linux computer, and the experience is okay, the executables are working fine but the set-up is a bit complicated, you need to copy files from the windows toolchain, copy your ldc config and edit it with some stuff, and do that at each ldc2 update. If you just need cross-architecture, then gdc is a good option since it is compiled in a lot of cross compilation toolchains. However, I never managed to build a working gdc myself with ucrt or mingw cross-compilation capabilities, it always ends up with a compiler unable to link or executables that can't be executed on Windows.
Indeed, at DeepGlance we are cross-compiling and cross linking with LDC and LLVM ld.lld, from macOS to linux. I'm interested in understanding if it's feasible to use importC with ffmpeg API and cross-compile and link them.
May 06 2023