I like dlang but i don't like dub

Adam D Ruppe destructionator at gmail.com
Sun Mar 20 12:27:54 UTC 2022


On Friday, 18 March 2022 at 18:16:51 UTC, Ali Çehreli wrote:
> As a long-time part of the D community, I am ashamed to admit 
> that I don't use dub. I am ashamed because there is no 
> particular reason, or my reasons may not be rational.


dub is legitimately awful. I only use it when forced to, and even 
making my libs available for others to use through it is quite an 
unnecessary hassle due to its bad design.

> That sounds great but aren't there common needs of those 
> modules to share code from common modules?

Some. My policy is:

1) Factor out shared things when I *must*, not just because I can.

So if it just coincidentally happens to be the same code, I'd 
actually rather copy/paste it than import it. Having a private 
copy can be a hassle - if a bug fix applies to both, I need to 
copy/paste it again - but it also has two major benefits: it 
keeps the build simple and it keeps the private implementation 
actually private. This means I'm not tempted to complicate the 
interface to support two slightly different use cases if the need 
arises; I have the freedom to edit it to customize for one use 
without worrying about breaking it for another.

When I must factor out it is usually because it is part of a 
shared public *interface* rather than an implementation detail. A 
shared interface happens when interoperability is required. The 
biggest example in my libs is the Color and MemoryImage objects, 
which are loaded from independent image format modules and then 
can be loaded into independent screen drawing or editing modules. 
Loading an image then being unable to display it without a type 
conversion* would be a bit silly, hence the shared type.

* Of course, sometimes you convert anyway. With .tupleof or 
getAsBytes or something, you can do agnostic conversions, but it 
is sometimes nice to just have `class SpecialImage { 
this(GenericImage) { } }` to do the conversions and that's where 
a shared third module comes in, so they can both `import 
genericimage;`.

2) Once I do decide to share something, there's a policy of tiers:

first tier has zero imports (exceptions made for druntime and 
SOMETIMES phobos, but i've been strict about phobos lately too). 
These try to be the majority of them, providing interop 
components and some encapsulated basic functionality. They can 
import other things but only if the user actually uses it. For 
example, dom.d has zero imports for basic functions. But if you 
ask it to load a non-utf8 file, or a file from the web, it will 
import arsd.characterencodings and/or arsd.http2 on-demand.

Basic functionality must just work, it allows those opt-in 
extensions though.

second tier has generally just one import, and it must be from 
the first tier or maybe a common C library. I make some 
exceptions to add an interop interface module too, but I really 
try to keep it to just one. These built on the interop components 
to provide some advanced functionality. This is where my 
`script.d` comes in, for example, extending `jsvar.d`'s basic 
functionality with a dynamic script capability.

I also consider `minigui.d` to be here, since it extends 
simpledisplay's basic drawing with a higher-level representation 
of widgets and controls, though since simpledisplay itself 
imports color.d now (it didn't when I first wrote them... making 
that change was something I really didn't want to do, but was 
forced to by practical considerations), minigui does have two 
imports... but still, I'm leaving it there.

Then, finally, there's the third tier, which I call the 
application/framework tier, which is the rarest one in my 
released code (but most common in my proprietary code, where I 
just `dmd -i` it and use whatever is convenient). At this point, 
I'll actually pull in whatever I want (from the arsd package, 
that is) so there is no limit on the number of imports. I still 
tend to minimize them, but won't take extraordinary effort. This 
is quite rare for me to do in a library module since this locks 
it out of use by any other library module! Obviously, no tier one 
or two files can import a tier three, so if I want to actually 
reuse anything in there, it must be factored out back to 
independence first.

C libraries btw are themselves also imports, so I also minimize 
them, but there's again some grey area: postgres.d use both 
database.d as the shared interface, but libpq as its 
implementation. I still consider it tier two though, despite a C 
library being even harder for the user to set up than 50 arsd 
modules.

3) I try to minimize and batch breaking changes, including breaks 
to the build instructions. When I changed simpledisplay to import 
color, it kinda bugged me since for a few years at that point, I 
told people they can just download it off my website and go.

I AM considering changing this policy slightly and moving more to 
tier two, so it is the majority instead of tier one. All my new 
instructions say "dmd -i" instead of "download the file" but I 
still am really iffy on if it is worth it. Merging the Uri 
structs and the event loops sounds nice, having the containers 
and exception helpers factored out would bring some real 
benefits, but I've had this zero-or-one import policy for so 
long, making it one-or-two seems too far. But I'll decide next 
year when the next breaking change release is scheduled.

(btw my last breaking change release was last summer and it 
actually broke almost nothing since i was able to migration path 
it to considerable joy. im guessing most my users never even 
noticed it happened)

> Despite such risks many projects just pull in code. (?) What am 
> I missing?

It is amazing how many pretty silly things are accepted as gospel.



More information about the Digitalmars-d-learn mailing list