Vibemail - extensions for vibe's Mail class to send multi-part emails with attachments

Adam D. Ruppe via Digitalmars-d-announce digitalmars-d-announce at puremagic.com
Tue Sep 29 09:22:41 PDT 2015


On Tuesday, 29 September 2015 at 14:57:13 UTC, Sebastiaan Koppe 
wrote:
> Good. But why put everything in one package?

dub forces me to do it that way. It isn't my preference, but 
reorganizing all my files and creating twenty or thirty different 
github repos to house them is unacceptable.

The unit of encapsulation in D is the module. If a module does 
two wildly different and independent things, you would break it 
up. Similarly, and I think this is often neglected, if two 
modules are intertwined and one cannot work without the other, 
they are really one unit and should be merged.

The merged module will present a cleaner interface and be easier 
to maintain since it can handle its own private implementation 
without worry of exposing internals for its friend module nor 
having something change independently of it.

(I wish D would fix that bug where public and private symbols can 
conflict though. So annoying and breaks this beautiful 
encapsulation. You might notice simpledisplay.d has a function 
named toInternal for example. I'd like to name it to, but then it 
would break code that uses std.conv.to, despite that internal 
function being private! Ugh!)

That forms the basis of my general policy: make modules that 
stand alone and do a task as completely as necessary. I only 
split them up when there's a technical requirement and the split 
lowers overall complexity.

And, of course, when possible, I like to make those dependencies 
optional; they aren't required unless you actually use those 
specific features.



Modules in D do a pretty good job at this. They can contain most 
their own metadata, too: write ddoc inline, you can grep it for 
version options (and since D doesn't allow versions to cross 
module boundaries, it is as simple as a grep) and import 
dependencies, and you can even have some control over the linker 
with stuff like pragma(lib), showing system dependencies.


Modules also have a one-to-one correspondence to files, making 
them a natural thing to download, move around, etc. Other 
programs know how to handle files so you can version them and 
such too.


D's modules work! Why does dub reject this model?

> A guy on npmjs.com goes the other extreme and he actually has a 
> package 
> (https://github.com/sindresorhus/negative-zero/blob/master/index.js) that consists of 1 line of code.

Disgusting. Think of all the overhead involved in that package, 
not just for the author, but now for everybody who use it... and 
everyone who uses something that uses it, and so on and so forth 
- right down to the end user!

There needs to be a balance struck between "don't repeat 
yourself" and avoiding dependencies.

It is generally considered a bad idea to do the whole system 
together at once. (though Docker and VMWare appliances and such 
do actually try to do that and have found some success in the 
market) Making changes to that means a lot of extra work that is 
easy to do wrong. (The duplication itself btw isn't a big problem 
to me, computers are good at doing the same thing over and over 
again; it is an easily automated problem, at least until 
something goes wrong.)

In code, we factor common functionality into functions that can 
be used from multiple places instead of copy/pasting the bodies 
everywhere.

It is similarly a bad idea to have a deep web of external 
dependencies. This also makes maintenance harder - where is the 
problem? Where do you make the change? How long will it take to 
get upstreamed? Do you understand what is going on anymore; will 
changing that dependency break some unrelated project somewhere 
else?

In code, we try to write our functions such that they do not use 
global variables. We like pure functions whenever we can. We like 
to use const or immutable to limit the scope of confusing 
changes. We like to use private to limit the function's interface.


Negative zero should be a constant (and probably a private one at 
that, that'd be a bizarre implementation detail to expose to an 
API user). Here, it is instead a public global mutable function 
pointer.


> In the description you say "or better yet, ditch dub and do 
> things the simple, reliable way of dmd *.d" How is that more 
> reliable?

It works the same way every time you do it and exposes all the 
options dmd has without needing wrapper json options which may or 
may not actually be there, or documented, or keep working the 
same way next time you try.

> I copy/pasted your arsd/dom.d code in a couple of projects. But 
> none of them will receive updates unless I do 'm manually.

That means you don't have to put up with me randomly breaking 
your code! You don't have to wait for me to publish a bug fix. 
You aren't locked in to the way I did things and are free to 
customize it as you wish.

It is very easy to update it too, even if you do customize it 
(git will handle the conflicts, if any) - you can always do a git 
pull from me, then test and push back up to your copy (or, not 
even bother with the push and just keep the development 
dependencies private or ask your users to retrieve it 
themselves... it is just a file download, very easy to do).

> However, the idea of having a package-manager is a good idea. 
> If only to serve as documentation on the libs you package 
> depends on.

dscanner --imports *.d | sort | uniq

Always up-to-date!

Though, dscanner and dub.json both fail to get across all the 
nuance possible with the D module system. For example, running 
that on dom.d yields:

arsd.characterencodings
arsd.database
arsd.jsvar


Yet, dom.d is also standalone!

characterencodings is only needed if you call one of the 
character conversion functions; it is a lazy local import inside 
a template.

database is the same, it is only used if you actually call the 
fillForm function. (Which is the only reason I permit that btw, 
dom and database should NOT depend on one another and I might 
just copy/paste that function out someday).

jsvar is only used with a rare -version switch that I never 
finished anyway. I should probably just delete those lines.


But, how do you express the half-dependency of characterencodings 
in a dub.json dependencies list? Perhaps a configuration could do 
it.... or the character converting functions could be pulled out 
into a third package on which you depend to get them.... what a 
pain compared to just "don't call this function and you never 
need it but if you want it it is right there"!


Here's how I documented it in dom.d:


/**
         BTW: this file optionally depends on 
arsd.characterencodings, to help it correctly read files from the 
internet. You should be able to get characterencodings.d from the 
same place you got this file.

         If you want it to stand alone, just always use the 
`parseUtf8` function
*/

That explains it better than dub.json has the capability to.




I'm not completely against the idea of a package manager or even 
against dub itself. I just see very little value add from it and 
quite a bit of complication and associated questions about it on 
the support forums.


More information about the Digitalmars-d-announce mailing list