Any estimates on having exceptions in betterC?

H. S. Teoh hsteoh at quickfur.ath.cx
Fri May 3 16:59:29 UTC 2019


On Fri, May 03, 2019 at 04:01:57PM +0000, Mike Franklin via Digitalmars-d wrote:
> On Friday, 3 May 2019 at 15:09:34 UTC, H. S. Teoh wrote:
> > Have the forums become so toxic that we can no longer use them for
> > what they're supposed to be used for -- to discuss exactly these
> > sorts of things??
> 
> Sorry if that came across the wrong way.  What I meant is that I find
> it difficult and sluggish to do much productive back-and-forth on the
> forums.  What I really need is to be able to quickly bounce ideas back
> and forth with like-minding, interested participants, and eventually
> arrive at a common understanding.  I find that difficult on the
> forums.  Chatting is better, and verbal communication is even better.
> I don't find the forums toxic, I just haven't found a way to utilize
> the forums to bring together common interests and arrive at a common
> understanding.  I'm ready to engage any one who's willing.
[...]

Fair enough.


> [...]  To achieve the opt-in continuum Andrei mentioned, I believe we
> need more modularity and less coupling.

Yes.  Phobos, in my mind, ought to be maximally pay-as-you-go, meaning,
if you don't use a particular feature, you pay nothing -- no new symbols
are imported, no functions or data ends up in the executable, no
TypeInfo's, etc..  Even the functions themselves should be designed in a
minimalistic way: if the user only needs the bare basics of an algorithm
without any frills, then there should be no hidden dependencies on said
frills.  (They can still be optionally available for those who want
them.)

An anti-example is std.format.format: the bare act of using
format!"%s"(str) pulls in *all sorts* of dependencies, like
floating-point formatting code, number-parsing code, and, last time I
checked, even std.bigint and/or std.complex, for whatever reason. Given
that we know the format string at compile-time, in theory we ought to be
able to eliminate all but the bare minimum required for that particular
format string to work.  If all we use is "%s", then it should translate
more-or-less to a single `write(fd, buf, buf.length)` call to the OS.
None of the other stuff like floating-point formatting code, needless to
say std.bigint / std.complex, should be pulled in.


> The first step towards that, IMO, is to create a utility library that
> has no dependencies whatsoever.  All other libraries, language
> implementations, and even the compiler itself could then begin their
> implementations by importing that fundamental utility library.  Of
> course, you wouldn't have to import it if you didn't want to, but it
> would be highly productive and idiomatic-D to do so.
[...]

I've given a lot of thought to reusable components lately. More and
more, I'm coming to the conclusion that proper API design is absolutely
essential.  If designed wrongly, an API will essentially *force*
dependencies upon all of its users, and this effect compounds across
multiple nested APIs, the end result being an inseparable hairball of
dependency hell that you have to either import all of it, or not at all.

There's too much to write about on this topic and I don't have the time
right now, but basically, APIs should as much as possible stick to
universal data representations (i.e., use built-in types as much as
possible, and avoid custom types unless absolutely indispensible; prefer
simple representations over complex, frilly ones); prefer no hidden
state or global state except where said state is the raison d'etre of
the module; be maximally decoupled: avoid exposing any data or functions
from dependencies (if module X depends on module Y for its
implementation, module Y should be completely invisible in module X's
public API), and be as composable as possible. If there's an existing
idiom for modules of similar functionality, use the existing idiom
rather than inventing a new one (don't reinvent the range API). As much
as possible, unify the style and structure of your APIs so that any
primitive X can serve as a drop-in for any other primitive Y. Minimize
special cases -- because they add complexity that compounds with every
additional API you use.  Make the absolutely minimal number of
assumptions you need to get your job done, and no more.  Etc.. Prefer
not having any dependencies at all, unless you absolutely cannot get the
job done without.  Remember, dependency resolution is NP-complete; avoid
dependency hell.

Preferably, the data you get from module X should be completely usable
with unrelated module Y, modulo trivial interconversion (though no
conversion at all is preferred). Similarly, an arbitrary function from
module X should be arbitrarily composable with any function from
unrelated module Y. Function signatures should be designed for maximum
composability and universality, and should avoid quirky parameter
ordering (e.g., std.algorithm.reduce vs. std.algorithm.fold) or
idiosyncrasies peculiar to that module.  As far as possible, every
function should be independently testable with minimal setup and no
global side-effects.

Gotta go, but there's a LOT to say on this topic.


T

-- 
Political correctness: socially-sanctioned hypocrisy.


More information about the Digitalmars-d mailing list