9 ms·
I don't like to be told what programming language i should use. You can scoff all you want, but i will be using C for most of my projects.
by gens 9y ago
I don't like to be told what programming language i should use. You can scoff all you want, but i will be using C for most of my projects.
- bluejekyll 9y agoI don't "tell" people, what language to use. But I do encourage them to look at new languages, especially ones that fit in the same place as one that they like. I love C. It was my first programming language. I love the syntax, I love the semantics. Years ago, I left it though, because I could deliver higher quality applications with fewer unknown bugs with Java, but I always wanted to find a reason to go back to C. And for some projects I did, and it was important (and in each case I'd run into some error or bug that took weeks to track down). When I grabbed Rust 2 years ago, it was like getting everything I loved about C paired with everything I love about Java, and none of the stuff I hate in either. Feel free to use whatever language you wish, and I hope schools continue to teach C (though that seems to be dwindling), but I highly encourage people to checkout Rust and see what it's like to not worry about pointer management all the time.
- Const-me 9y agoWhen I checked out Rust a year ago, I immediately discovered it has no SIMD (SSE, AVX, Neon). That it has no sane ways to implement a graph structure. Also that it’s hard to compose data structures into higher-level specialized ones. Also, I highly encourage people who worry about pointer management all the time to checkout modern C++.
- pcwalton 9y ago> That it has no sane ways to implement a graph structure. Sure it does. I work with graphs in Rust all the time. They may not be "sane" in your view because they're different from the way you implement them in C++, but I could equally well say that there's no "sane" way to implement a safe owning pointer in C++ (since there's no memory-safe way to do so). > Also, I highly encourage people who worry about pointer management all the time to checkout modern C++. Modern C++ has no protection against the most pernicious memory management errors, particularly use-after-free.
- Const-me 9y ago> They may not be "sane" in your view because they're different from the way you implement them in C++ I saw two kinds of Rust graphs. One is safe, easy to understand, but slow (e.g. reference counting). Another one (unsafe Rust) is very hard to implement, thousands lines of code. Also, modern C++ is much safer than unsafe rust. > C++ has no protection against the most pernicious memory management errors, particularly use-after-free CRT debug heap / MALLOC_CHECK_ / libefence, depending on the platform/compiler
- cesarb 9y ago> I saw two kinds of Rust graphs. There's a third kind, which uses indexes into arrays containing the nodes and edges, instead of direct pointers to the node/edge. > CRT debug heap / MALLOC_CHECK_ / libefence, depending on the platform/compiler Can any of these protect against the scenario where a block of memory is freed, allocated again for another purpose, but still accessed through the old dangling pointer? Also, are they always present at runtime, or are they used only on debug builds and turned off on production? The use-after-free might happen only after a specific sequence of uncommon operations confuses the code enough that it either frees something before its time, or keeps and uses a stale pointer.
- Const-me 9y ago> There's a third kind, which uses indexes into arrays containing the nodes and edges Pointers are still faster. Also with arrays it’s expensive to reduce RAM usage after a lot of nodes were removed. > Can any of these protect against the scenario where a block of memory is freed, allocated again for another purpose, but still accessed through the old dangling pointer? No 100% guarantee, but AFAIR CRT debug heap takes measures to reduce RAM reuse when it can. > are they always present at runtime, or are they used only on debug builds Not present. Yes, only on debug builds. Still, these early debug traps are quite helpful while development.
- cesarb 9y ago> Pointers are still faster. Depending on cache effects, indexes might or might not be faster than pointers. With indexes into an array, the nodes or edges will be sequential in memory, which depending on their size and access patterns might increase the cache hit rate. Furthermore, while pointers will always be 8 or 4 bytes, indexes can be as small as 2 or even 1 byte for smaller graphs (reducing structure sizes and potentially leading again to a higher cache hit rate). As for the costs of indexing, on x86 a single instruction can add the array base, the index, and a constant offset, and do a load or store from/to the resulting address. Other architectures might need a few more instructions, but that is dwarfed by the cost of a cache miss, which can be hundreds of instructions. Another cost is the bounds check for every indexing into the array, which the compiler can't elide because it can't easily prove that the index is within the array bounds. That is the main reason you saw "unsafe" code on the petgraph crate; there are places where the programmer knows the indexes are within the bounds, since they came from a trusted place (the graph itself), but the compiler isn't smart enough to prove it, so the programmer manually bypasses the array bound checks in these cases. All in all, I wouldn't know a priori which would be faster for a particular use case, pointers or array indices. I'd have to benchmark first. > Also with arrays it’s expensive to reduce RAM usage after a lot of nodes were removed. True, the "array indexes" approach is not as good for algorithms which need to remove many nodes (or edges, depending on how they're represented) from the graph. As long as you don't need the indexes to be stable across deletions, you can use a simple trick to make deletions cheaper (move the last element of the array into the newly freed place, so all empty places are at the end of the array), but that trick can't be used if you need the indexes to be stable (because they're referenced from outside the graph).
- bluejekyll 9y agoGraph in Rust: https://github.com/bluss/petgraph https://github.com/bluss/petgraph SIMD in Rust: http://huonw.github.io/blog/2015/08/simd-in-rust/ http://huonw.github.io/blog/2015/08/simd-in-rust/ (yes, still in nightly)
- Const-me 9y ago> Graph in Rust: https://github.com/bluss/petgraph https://github.com/bluss/petgraph Thousands lines of code. Large amount of that is unsafe rust, even C++ is safer than that :-) > SIMD in Rust: http://huonw.github.io/blog/2015/08/simd-in-rust/ http://huonw.github.io/blog/2015/08/simd-in-rust/ (yes, still in nightly) It was already “still in nightly” a year ago. Also it’s harder to do integer math with it, because type safety: very often, even consecutive instructions interpret these __m128i registers as different datatypes, u8x16 / i32x4 / u64x2 / etc.
- pcwalton 9y agopetgraph is a lot of code because it has a lot of features. You could equally well criticize C++ because boost is so much code. A simple graph with indices is a lot smaller, and it doesn't need unsafe either.
- kibwen 9y ago> Thousands lines of code. Have you taken a look at petgraph? It does quite a lot of things. The same functionality in C would be thousands of lines as well. > It was already “still in nightly” a year ago. SIMD is in Rust nightly not because it's immature, but because the Rust developers would rather design a portable interface than quickly standardize a nonportable one. Given that AFAIK neither the C nor C++ specifications include provisions for SIMD and all support is compiler-specific, the only difference between C/C++ and Rust here is that Rust follows a release model that features a nightly channel.
- Const-me 9y ago> neither the C nor C++ specifications include provisions for SIMD and all support is compiler-specific The support is portable across compilers. You #include <[xepsiz]mmintrin.h>, and you’ll get these SIMD intrinsics as documented on intel.com. BTW, OpenMP isn’t in the C++ language spec either, doesn’t prevents it from working on most compilers and platforms.
- josephg 9y agoWhen I checked out rust a year ago, I tried to implement three things: - Some OT code. This went ok, but I still have no idea which of the 6 string types I should use for a library like that. I think I ended up settling for Rc<Cow<String>> or something, but it still wasn't ideal. Swift, Go and C all each have a canonical string type. - First I tried to make a skip list with performance matching the performance of my C implementation. I discovered that even with unsafe there was no way to make a struct with a dynamically sized array at the end, like I can easily do in C. - Then I tried to make a networked server using tokio. Despite all the hype, adding a dynamic item to the event bus didn't work because it wasn't 'static didn't work. After spending a few hours fighting the borrow checker, I went online and was told that this would get better with impl trait or something. I'd really like to use rust, but as far as I can tell its not mature enough for what I want. I've started a new server project recently and I'm writing it in straight C, as none of the newcomer C-replacement languages I tried seem good enough to replace C.
- pcwalton 9y ago> This went ok, but I still have no idea which of the 6 string types I should use for a library like that. None of Swift, Go or C have this problem. There are two string types: a string that owns its contents and a string that references its contents. This is the same as in any language that uses smart pointers for resource management. Can you name a string type that you think should be removed, and explain why? > First I tried to make a skip list with performance matching the performance of my C implementation. I discovered that even with unsafe there was no way to make a struct with a dynamically sized array at the end, like I can easily do in C. Yes, you can. You can make a one element array and allocate and deallocate manually, just as you do in C. The offset method on pointers allows for arbitrary pointer arithmetic. > Despite all the hype, adding a dynamic item to the event bus didn't work because it wasn't 'static didn't work. I haven't used Tokio, but couldn't you use a boxed trait?
- josephg 9y ago> There are two string types: a string that owns its contents and a string that references its contents. This is the same as in any language that uses smart pointers for resource management. There's String, &str, Cow<?>, Rc<?> and other variants. None is canonical. I spent about 2 hours reading documentation trying to pick the right type to use and I think I ended up with Rc<Cow<String>>. But in this instance my strings represent character edits in a document. 90% of the time they're < 5 bytes long. So in 90+% of cases I should be able to avoid allocations and memory dereferencing entirely, and store the string inside the pointer. What I actually want is an efficient version of enum Str { ShortStr(char[X]), Ref(Rc<Cow<String>>) }, but encapsulated behind a common string interface. Coincidentally, this is exactly how the canonical string implementation works in obj-c and (I think) swift. Despite having 6 different options maybe the string type I actually want is buried in Cargo. I'm not sure - at this point I was tired and I stopped trying. To me this is a classic symptom of a language trying to do too much. Having all this choice is great for systems development, but for application-level development I don't want X different string options. You want 1. And I want it to be good. Having lots of options would be fine if the language was more opinionated - "Unless you know what you're doing you should just use String, which is efficient, immutable, copy-on-write and ref counted. Click here (link to advanced section of book) to read about your other options if you want more control over allocations." > Yes, you can. You can make a one element array and allocate and deallocate manually, just as you do in C. The offset method on pointers allows for arbitrary pointer arithmetic. Does it? At the time even with unsafe there was no way to directly call malloc. Maybe I just couldn't find it in the docs, or maybe thats changed now. I spent weeks on and off trying to get it working, including reading the rust unsafe nomicon and writing dozens of linked list implementations. I tried out all sorts of weird ways to allocate and initialize the array. I kept thinking of new ideas, only to find out a critical piece of syntax was missing. In the end I could allocate the struct I wanted but discovered it was syntactically impossible to initialize, or something silly like that. And at that point I gave up. Maybe this problem has been fixed since. And maybe if I spent even more time trying I would have figured it out. But I was tired and I had work to do. > I haven't used Tokio, but couldn't you use a boxed trait? I don't know what that is. Frankly I'm still confused why Rc<> didn't work. I got about 6 different answers when I asked the rust subreddit how to fix this. Some people suggested things that also didn't compile. Some people said I should make my object 'static (no thanks). And others said the problem would be fixed when trait impl lands (whatever that is - is that what you're talking about?). This use case is literally the 'hello world' of nodejs code - attach an event handler to an object, interact with local variables each time the event fires. At least as of a year ago the tokio devs clearly thought all network servers only did request/response style interaction. All the examples on their website were either an echo server or an http server. I need streams. I really want to be able to use rust. But so far my only experience with it has been one of frustration. It seems too immature to replace C as a systems language, and tokio seems too immature to replace Nodejs for network services. Maybe I'll revisit it in a few years, but at this point I'm more hopeful either someone will bolt decent syntax on top of Go a la coffeescript, or that Swift will add language level support for concurrency. (I'd be happy with either async or go's actor model.)
- na85 9y agoI haven't learned rust because of how annoying the rust evangelism is everywhere I read about it.
- gens 9y agoI don't know why it is not common knowledge that different people have different priorities, different ways of thinking about things and, well, that they are different. Not only that but people can even have opinions that contradict their other opinions. I write C, its powerful and that it stays out of the way. I also like assembly for the same reasons. But i also like scheme, that is the most opposite language to C that i know of. Another reason i like these three languages in particular is that they are simple. There are no added features that would make me look them up, if, for example, i was reading somebody elses code or if i didn't code in a few months. I like my data to be laid out how i want it and process it how i want it. You can say "but rust lets you do it with this", when in C i "just do it". The whole memory safety argument is.. i want to say "fine" as people do make mistakes, but tools like static analyzers (aka linters) and valgrind exist. As for the higher social aspect; > I don't "tell" people, what language to use. But you do. If you say to a newbie that their C project is "bad" because it is written in C, be it directly or indirectly, they will take it as if you are telling them to use another language (and when you say that that language is Rust, then.. well..). When the truth is that programming languages don't matter in most cases. > But I do encourage them to look at new languages, especially ones that fit in the same place as one that they like. I couldn't agree more, with the first part at least. I like imperative programming more then pure functional, but i did learn a lot by programming functionally in scheme (and by playing with some other languages that i will never use), and now the C that i write is better for it. edit: assembly is a good example of a language to learn just for the sake of knowing it. Let us mention that learning abstract theory things also influences how we write things in a specific language. Things like the million forms of data structures and various.. ways of doing things (graph theory (that is surprisingly relevant to concurrency), touring machines vs lamda calculus, various ways of sharing state between parts of code, and.. i can't think of more now). In addition to that, how a computer works can also shape how we program. We have limitations, for example it is very important for performance to not trash the cpu cache all the time. Now to go back to "reality"; Software is (usually) written to be used. Things that matter are what it does and its cpu/memory usage. For a program that is used to, idk, process some text once a month it doesn't matter what it is written in. But if the program is to be used daily on thousands of computers it starts to be more important that it performs well. That is my opinion at least, as the general opinion seems to be "modern computers have so much processing power and gigabytes of memory". Personally it pisses me of when a vital part of a system is hacked together so it "works", where examples are Glib usage in NetworkManager (and many others), and python (i rewrote phwmon in C because it uses too much memory and cpu, maybe some day i'l clean it and post it on github). If something is vital for day-to-day usage of a computer, then it better well not use hundreds of megabytes of memory and 100 times more cpu then it should (note that 100 times more cpu usage for many "system" things is still a tiny amount, but regardless). To paraphrase a quote that i can't find anymore "the best daemon/program is one that does its job but you don't know it is running", where an example would be dhcpcd (currently uses 196kB of memory and it used a total of 0.05 seconds of a cpu core (klogd is even better with 80kB of memory and 0.02sec cpu time)). Then there are domain specific languages.. EDIT: I would also like to add that as much as we are different from each other, we are also much the same. And that we can change the ways we think, for better or worse (not that anything is either black or white).
- quickben 9y agoI am fluent in c, c++, c#. The performance level difference in implementations in some cases is over five orders of magnitude. I envy people that don't have to worry or use pointer management. I imagine them coding in rust with one hand while drinking martinies with the other :)
- bluejekyll 9y agoThis is exactly how I code, well s/martinies/burbon/. ;) The compiler makes sure those types I'm seeing double of are legit. Seriously, there's a reason the moto 'fearless programming' has been applied to Rust.
- Jtsummers 9y agoThat's one of the main reasons Ada lost to C and C++ in the DoD world. The other (and more significant) being cost of implementations. Personally, I prefer my work to be in the language or languages which suit it best rather than making my choice to spite others for a perceived and, usually, non-existent slight.