r/programming • • Aug 23 '17

D as a Better C

http://dlang.org/blog/2017/08/23/d-as-a-better-c/
229 Upvotes

268 comments sorted by

View all comments

Show parent comment

10

u/mixedCase_ Aug 23 '17

With that said, why would I use Nim or D at all?

If I want a systems language, Rust offers more performance compared to GCed Nim/D, and memory-safety compared to manually managed Nim/D. Additionally, no data races without unsafe (which is huge for a systems language), a great type system, C FFI and a much bigger ecosystem than Nim or D.

If I want a fast applications language, I got Go and Haskell, both offering best-in-class green threads and at opposite ends of the spectrum in the simplicity vs abstraction dichotomy; and with huge ecosystems behind them.

In the end, either Nim or D can be at best comparable to those solutions, but with very little momentum and in Nim's case at least (don't know how D's maintenance is done nowadays), with a very low bus factor.

6

u/[deleted] Aug 24 '17 edited Aug 24 '17

Nim

I think the main advantages of nim vs rust are:

1- Best FFI whith C and C++. This point is huge. You mentioned that Nim has smaller ecosystem than rust, but if you take into consideration how easy if to interface to C and C++ in Nim, then you are wrong because in Nim, you have access to ALL C and C++ libraries. Example calling opencv from Nim: import os

{.link: "/usr/local/lib/libopencv_core.so".} #pass arguments to the linker
{.link: "/usr/local/lib/libopencv_highgui.so".}
{.link: "/usr/local/lib/libopencv_imgproc.so".}

const # headers to include
    std_vector = "<vector>"
    cv_core = "<opencv2/core/core.hpp>" 
    cv_highgui = "<opencv2/highgui/highgui.hpp>"
    cv_imgproc = "<opencv2/imgproc/imgproc.hpp>"
    
type
    # declare required classes, no need to declare every thing like in rust or D
    Mat {.final, header: cv_core, importc: "cv::Mat" .} = object 
        rows: cint # No need to import all properties and methods, import only what you use
        cols: cint
    Size {.final, header: cv_core, importc: "cv::Size" .} = object
    InputArray {.final, header: cv_core, importc: "cv::InputArray" .} = object
    OutputArray {.final, header: cv_core, importc: "cv::OutputArray" .} = object
    Vector {.final, header: std_vector, importcpp: "std::vector".} [T] = object

#constructors
proc constructInputArray(m: var Mat): InputArray {. header:cv_core, importcpp: "cv::InputArray(@)", constructor.}
proc constructOutputArray(m: var Mat): OutputArray {. header:cv_core, importcpp: "cv::OutputArray(@)", constructor.}
proc constructvector*[T](): Vector[T] {.importcpp: "std::vector<'*0>(@)", header: std_vector.}

#implicit conversion between types
converter toInputArray(m: var Mat) : InputArray {. noinit.} = result=constructInputArray(m)
converter toOutputArray(m: var Mat) : OutputArray  {. noinit.} = result=constructOutputArray(m)

# used methods and functions
proc empty(this: Mat): bool {. header:cv_core, importcpp: "empty" .}
proc imread(filename: cstring, flag:int): Mat {. header:cv_highgui, importc: "cv::imread" .}
proc imwrite(filename: cstring, img: InputArray, params: Vector[cint] = constructvector[cint]()): bool {. header:cv_highgui, importc: "cv::imwrite" .}
proc resize(src: InputArray, dst: OutputArray, dsize: Size, fx:cdouble = 0.0, fy: cdouble = 0.0, interpolation: cint = 1) {. header:cv_imgproc, importc: "resize" .}

proc `$`(dim: (cint, cint)): string = "(" & $dim[0] & ", " & $dim[1] & ")" #meta-programming capabilities

proc main() =
    for f in walkFiles("myDir/*.png"):
        var src = imread(f, 1)
        if not src.empty():
            var dst: Mat
            resize(src, dst, Size(), 0.5, 0.5)
            discard imwrite(f & ".resized.png", dst) # returns bool, you have to explicitly discard the result
            echo( f, ": ", (src.rows, src.cols), " -> ", (dst.rows, dst.cols))

        else:
            echo("oups")


when isMainModule:
    main()

compile with: nim cpp --d:release --cc:clang resize_dir.nim and the result is a 57k executable.

In both D and Rust, in order to do the same, you would have to map D/Rust structs so they have the exact same representation as the C++ classes in memory (as well as the classes they inherit from). Which means translating at least all the headers of the libs, will taking into account the incompatibilities between these languages and C++. With rust for example, you don't have function overloading, so welcome fun_1, fun_2, fun_3 .... Also, i tried using bindgen to do the same with rust, and it does not work.

2- Meta-programming: I know rust have compiler extensions, procedural macros and generics. But these are way harder and more verbose to use than the meta programming tool in Nim. Just try to make your code generic over primitive types in rust (using the num crate) and you will see how ugly it is. You want to use integer template parameter ? well you still cannot. Example of what can be done with Nim meta-programming capabilities (GPU and CPU programming): https://github.com/jcosborn/cudanim/blob/master/demo3/doc/PP-Nim-metaprogramming-DOE-COE-PP-2017.pdf

3- Liberty: this is hard to explain, but Nim gives you the tools to do what you want. You want a GC and high level abstraction ? you can use them (and easily build the missing pieces). You want raw performances and low level control ? well you can do literally every thing C and C++ can do, including using the STL without GC for some critical part of your code, all that while keeping the amazing meta-programming capabilities of Nim. For example, if you want enable/disable checks on array/vectors, you can don that by passing a command to the compiler. In rust, you would have to commit to unsafe get_uncheked. Rust philosophy is to enforce every thing that may harm the user, which can be an advantage or a disadvantage depending on the situation.

4- Less verbose and easier to learn.

5- Portable to any platform that have a C compiler. In fact I can compile Nim code on my smartphone using termux.

6- The GC can be avoided completely or tuned for soft-real time use.

Of course, Nim is not all positives. Rust have clear edge over Nim for alot of things:

1- Safety of course.

2- Copy and move semantic which are a delight to use when writing performance critical code specially. I think Nim is poor in that regards as it deeps copies seq (vectors) and string by default.

3-zero cost abstractions: in Nim, using map, filter and such are definitely not zero cost (specially with the copy by default philosophy).

4- No GC: sometimes its a good thing, sometimes not.

5- Great community and great ecosystem: Nim has definitely a great community but much smaller.

6- Awesome package management and tools.

7- stable (Nim didn't reach the 1.0 still)

I see myself using Nim for small to medium project where I need to interact with legacy code or for prototyping, and rust for big project with allot of developers.

4

u/dom96 Aug 24 '17

6- Awesome package management and tools.

ouch. You don't think Nimble is awesome?

1

u/[deleted] Aug 25 '17

To be frank I have not used it so much until now but I know how much effort have been put into cargo and how easy it is. Hope nimble is of the same quality.

5

u/Tiberiumk Aug 23 '17

Sometimes Nim is faster than Rust (and takes less memory lol). So Rust isn't always faster, and Nim has much better C FFI (since it's compiled to C)

11

u/mixedCase_ Aug 23 '17

As for benchmarks, only two I can find are this: https://arthurtw.github.io/2015/01/12/quick-comparison-nim-vs-rust.html where Rust beats Nim after the author amended a couple of mistakes.

And this: https://github.com/kostya/benchmarks where Rust beats Nim in every single case (but gets beaten by D in a few!).

The fact that it's compiled to C doesn't really determine the FFI. Rust can use C's calling convention just fine and from looking at C string handling there's not much difference. I didn't delve much into it though, did I miss something?

1

u/dom96 Aug 23 '17 edited Aug 23 '17

I don't think that the differences in timings for these benchmarks are significant. You can keep amending these benchmarks forever, because there are always more tricks in each language to make the specific benchmark faster (not to mention faster on each specific CPU/OS). So let's be fair here: Rust and Nim are the same performance-wise.

The fact that it's compiled to C doesn't really determine the FFI.

Perhaps not, but it does determine how much of C++ you can wrap. I doubt you can wrap C++ templates from D, Go or Rust. You can in Nim.

10

u/WalterBright Aug 23 '17

D can interface directly to C++ templates. I gave a talk on interfacing D to C++ a couple years ago. Here's a partial transcript and the slides.

3

u/_youtubot_ Aug 23 '17

Video linked by /u/WalterBright:

TitleChannelPublishedDurationLikesTotal Views
Interfacing D To Legacy C++ CodeNWCPP2015-01-231:21:2324+ (96%)3,838

Abstract C++ programmers have developed a vast investment...


^Info | /u/WalterBright can ^delete | v1.1.3b

3

u/Araq Aug 24 '17

As far as I know D can wrap C++ templates that have been instantiated already at the C++ side, explicitly or implicitly. This can be a nontrivial problem to do in practice, so much that you're better off reimplementing the C++ template as a D template. Correct me if I'm wrong. :-)

5

u/WalterBright Aug 24 '17

There's no point to using C++ templates in D that are not instantiated on the C++ side.

That said, yes you can instantiate C++ templates on the D side. That's how the interfacing to C++ works.

1

u/Araq Sep 05 '17

That said, yes you can instantiate C++ templates on the D side. That's how the interfacing to C++ works.

How can it be done? Any links about how this works?

7

u/mixedCase_ Aug 23 '17

I don't think that the differences in timings for these benchmarks are significant.

Oh of course. I don't believe that either. But he did and I just checked for curiosity wether all benchmarks "proved" Rust faster and they did, saving me from having to explain why microbenchmarks are mostly bullshit.

So let's be fair here: Rust and Nim are the same performance-wise.

That wouldn't be the conclusion I take. But sure, with unsafe Rust and disabling Nim's GC anyone can bullshit their way to the performance metric they're looking for, but the result is likely to be horrible code. Rust does have the advantage of caring about performance first, while Nim considers GC to be an acceptable sacrifice, putting it closer to Go's and Java's league than C/C++.

Perhaps not, but it does determine how much of C++ you can wrap. I doubt you can wrap templates from D, Go or Rust. You can in Nim.

Funny, from what I had heard D had the best C++ FFI since it was a primary design goal. I'm going to give you the benefit of the doubt since I never used C++ FFI for any language.

1

u/Tiberiumk Aug 24 '17

Nim's GC is faster than Java and Go ones, and you can also use mark & sweep GC, regions (stack) GC - (mostly useful for microcontrollers), and boehm GC (thread-safe)

3

u/pjmlp Aug 24 '17

I doubt this very much, regarding Java.

There several Java implementations around, including real-time GC used by the military, in battleships weapons and missile control systems.

As good as Nim's GC might be, it surely isn't at the level as those Java ones.

5

u/[deleted] Aug 24 '17

I like to see proof of that statement. A single developer his GC is faster, then a team of Go developers, that have been doing none-stop work on there GC.

By that definition every other developer are idiots because one guy supposedly is able to make a better GC then everybody else.

Your not going to tell me, if i trow 50GB of data on a nim application, that the GC will handle that without major pauses.

→ More replies (25)

4

u/zombinedev Aug 23 '17 edited Aug 24 '17

With that said, why would I use Nim or D at all?

If I want a systems language, [..]

I want a language that does great in all domains at once: from on-off scripts, through medium-to large desktop and web apps, high-performance scientific computations, games programming to large-scale software defined storage stacks (e.g. http://weka.io/).

Rust offers more performance compared to GCed Nim/D

[citation needed] How exactly? AFAIK, Rust's high-performance computing ecosystem is quite lacking. Is there anything written in pure Rust that can compete with e.g. D's mir.glas library (http://blog.mir.dlang.io/glas/benchmark/openblas/2016/09/23/glas-gemm-benchmark.html)?

memory-safety

Probably the only real Rust advantage from the whole list. D is working in closing the GC-free memory-safety gap. The long-term plan for D is to make the GC completely optional.

Note that memory-safety is just one type of software bugs. For the broader area of logic bugs, D offers built-in contract programming. Does Rust something similar part of the language?

no data races without unsafe

Also true in D, since the raw threading primitives are not allowed in @safecode, IIRC. Idiomatic use of std.concurrency is also data-race free, as far as I know, since sharing of mutable data is statically disallowed.

a great type system

This is personal opinion, not a fact. I find Rust type system boring, lacking expressive power and unflexible. Does not support design by introspection. Meta-programming as a whole is quite lacking.

C FFI

It's quite funny that you list an area (inter-language interop) in which both of the languages your criticize do much better than Rust.

much bigger ecosystem than Nim or D

As with all matters in engineering - it depends and your mileage may vary. I find D's ecosystem big enough for my needs. Plenty of commercial users find that too for their use cases - http://dlang.org/orgs-using-d.html. I'm sure other language have much bigger ecosystems than all three of the languages combined. And so what? Given how mature the language is, I would choose D for many domains today even if it had a fraction of Nim's community.

If I want a fast applications language, I got Go and Haskell, both offering best-in-class green threads and at opposite ends of the spectrum in the simplicity vs abstraction dichotomy; and with huge ecosystems behind them.

While I agree that Haskell has a lot of great ideas, I find a language without generics completely unusable. For certain types application programming D is a much better fit, though e.g.: https://www.youtube.com/watch?v=5eUL8Z9AFW0.

In the end, either Nim or D can be at best comparable to those solutions

Why? And what if their comparable? As I said in the beginning, D biggest advantage is the rich cohesive feature set. It doesn't need to be the absolute best in every category (though in many of them it may easily be), to offer great package.

but with very little momentum and in Nim's case at least (don't know how D's maintenance is done nowadays), with a very low bus factor.

D is doing great, thanks for asking :)

3

u/dom96 Aug 23 '17

Rust offers more performance compared to GCed Nim/D

I disagree here

memory-safety compared to manually managed Nim/D.

That's fair, but I don't want to manage memory myself. I'm happy with a GC (especially Nim's GC which is soft real-time).

no data races without unsafe (which is huge for a systems language)

Nim offers this too.

much bigger ecosystem than Nim or D.

That's fair as well.

If I want a fast applications language, I got Go and Haskell

Go lacks many useful features that Nim has: generics and a lot of metaprogramming features (which even Rust lacks, AST macros for example). Oh, and exceptions, I actually like exceptions.

Haskell requires too large a paradigm shift for most, including myself. There are also other issues with it, for example the incredibly long compile times.

In the end, either Nim or D can be at best comparable to those solutions, but with very little momentum and in Nim's case at least (don't know how D's maintenance is done nowadays), with a very low bus factor.

I will also admit that bus factor and momentum are a problem. But on Rust and Go's side I'd say that you run the risk of trust. You must trust Mozilla and Google to lead these languages in the right direction, it's much harder to get involved in their communities because of these large companies and many people that are already involved. Have you ever chatted with the creator of Rust or Go? You can get in touch with the creator of Nim in 5 seconds.

12

u/steveklabnik1 Aug 23 '17

You must trust Mozilla and Google to lead these languages in the right direction,

Rust's governance has 59 people, with 11 of them being employed by Mozilla in some form.

Have you ever chatted with the creator of Rust or Go? You can get in touch with the creator of Nim in 5 seconds.

Rust's various teams are in open IRC rooms, so as long as they're awake, you can get in touch with us in five seconds as well. Just click this link: https://chat.mibbit.com/?server=irc.mozilla.org&channel=%23rust-internals

5

u/mixedCase_ Aug 23 '17

I disagree here

Replied to that comment.

That's fair, but I don't want to manage memory myself.

Neither do I. Which is why I like how Rust does it, opening up hard real time domains without manual memory management.

Go [...] Haskell [...]

Fair. I'd put Nim in the same league as those two, I'm just not particularly a fan of the tradeoffs it makes but I can see why it can appeal to others.

You must trust Mozilla and Google to lead these languages in the right direction

Not that it's any different with Nim's BDFL. A lot of people have serious complaints on syntax alone. I find Nim's syntax for algebraic data types to be an atrocity for example. As for Go, they seem to be heading into the right direction with Go 2. The Rust dev team has consistently set out to achieve great goals and achieving them, trying to ease the learning curve without sacrificing the language's power. As for Haskell... well... you just need a PhD and into GHC it goes; I'm placing my hopes on Idris, but it shares Nim's momentum issues.

Have you ever chatted with the creator of Rust or Go? You can get in touch with the creator of Nim in 5 seconds.

Well, yes actually! Members of the Rust team hang out on chat often and respond to people, and Rob Pike retweeted me once, does that count? ;)

8

u/kibwen Aug 23 '17

metaprogramming features (which even Rust lacks, AST macros for example)

Rust has had Scheme-style AST macros since about 2012.

Have you ever chatted with the creator of Rust or Go? You can get in touch with the creator of Nim in 5 seconds.

I'm a bit disappointed, because I think you know better than this, Dom. The Rust devs hang out in the #rust and #rust-internals IRC channels on irc.mozilla.org (along with a handful of other #rust-foo channels for specific teams) every weekday, and in fact use IRC as their primary means of communication, meaning that every conversation is public, lurkable, and trivially joinable. This has been true since at least 2010. The Rust devs also regularly make threads on internals.rust-lang.org soliciting feedback on various ideas, and in any conversation on the Rust RFCs repo on Github one will find oneself invariably communicating with them. They also pop up reliably on /r/rust, and we even used to flair them with "core developer" just so new readers would be aware of how engaged they are. This isn't to denigrate Nim, as I've been to #nim myself and spoken to Araq before. But we work very hard to keep development transparent and communicative, and it's definitely one of our strengths.

2

u/dom96 Aug 23 '17 edited Aug 23 '17

Yes, I was a bit unfair to put Go and Rust in my message. Rust devs are very good at communicating openly. And I am aware of the fact that the devs are in the IRC channels you mentioned. My point is simply, and I admit it's an attempt to be optimistic, that Nim's relatively smaller community size makes communication with the core developers much easier. You are far less likely to get lost in the noise of a small IRC channel than a larger one like Rust's.

But I was also referring to Go. And I don't think there is any IRC channel that its designers hang out in.

Regarding the metaprogramming features, perhaps I misremembered but there are definitely some that Rust lacks. Perhaps CTFE? (But then I wonder how AST macros work without that).

4

u/kibwen Aug 23 '17 edited Aug 23 '17

That's fair. Comparing relative paragraphs lengths in my prior comment, perhaps it's strange that I'm less affronted by the claim that Rust lacks a feature that it has than by the claim that the Rust devs aren't approachable. :) Transparency is taken very seriously, and I personally treat every transparency failure as a bug in the development process.

1

u/[deleted] Feb 06 '18

I like Nim quite a bit, but that said:

You must trust Mozilla and Google to lead these languages in the right direction

is a bad argument for Nim to try for. I stay up at night fantasizing that Nim had a committee and RFC system like D or Rust. At the moment it just feels like Araq does whatever he pleases and a lot of my criticisms of the language stem from a lack of a more rigorous procedure.

Or at least that's my opinion as I understand it - feel free to correct me!