4 ms·
I don't want to be that guy but I don't see this language as usable. Not because of technical reasons but because... I mean... look at it. I can't understand wh
by gravypod 10y ago
I don't want to be that guy but I don't see this language as usable. Not because of technical reasons but because... I mean... look at it. I can't understand what's going on. It's way too complicated.
type Vector* {.importcpp: "std::vector", header: "<vector>".}[T] = object
template `[]=`*[T](v: var Vector[T], key: int, val: T) =
{.emit: [v, "[", key, "] = ", val, ";"].}
What the hell does that mean?How the hell do I check this is correct at a glance?
I know "it's easy", "you'll get used to it", "after you learn the syntax it'll be great" but I mean... no one is going to buy that.
I get that it's supposed to be condenced but I don't necassarily buy that as being the end-all-be-all of language construction. I think that's actually quite harmful to programmers. If a single character means the same as 10 lines of a simpler language then you're more likely to hide a mistake in your code.
I'm not saying it's wrong either, I'm just saying a majority of programmers will be afraid of it. I rather like what swift is trying to do with condensing well-known operations but I don't think Nim and many other ML-inspired languages do it in an approchable way.
- majewsky 10y agoIt took me a moment to parse, but that snippet is actually pretty straight-forward when you know that Nim compiles down to C (or C++). type Vector* {.importcpp: "std::vector", header: "<vector>".}[T] = object This obviously creates a type "Vector" whose underlying implementation is C++'s "std::vector". (I don't know how writeable it is, but it is* readable.) template `[]=`*[T](v: var Vector[T], key: int, val: T) Function declaration syntax for operator overloads is hard to make readable (as in: familiar). In fact, this is about as readable as it can get (although I'm confused by the "*[T]"). = {.emit: [v, "[", key, "] = ", val, ";"].} As I said, when you know that the compiler generates C code, this makes a lot of sense. It's a compiler instruction to compose a string of C code.
- evacchi 10y ago> (although I'm confused by the "[T]"). the `*` marker means that the proc/template is "public" (not local to the module)
- vgbm 10y agoTo supplement the other response, [T] declares a generic type, so [T] is a public method with the generic type T. I'd agree though that the is initially hard to parse, especially when taking C and C++ into account, where * means something entirely different.
- pathsjs 10y agoWell, the example you are looking at is very complex, but also you are very unlikely to run into it early! For better examples, look at the homepage: you will see something much more approachable. The reason this snippet is complex is that: 1. It deals with the Foreign Function Interface 2. It deals with the FFI with respect to C++, which is much more complex than the one towards C, essentially because C++ itself is complex 3. It uses a particular construct (emit) that is only needed when the standard FFI is not enough So the example is really a showcase of a particularly complex case that you will likely not encounter, unless you start wrapping C++ libraries (which is not an easy task, unlike the C ones)
- gravypod 10y agoThat was the first code snippet on the website that I saw.
- mrkgnao 10y agoMacros implemented with ... string interpolation? This looks like a suboptimal idea. Edit: I spoke too soon. This looks like code generation, and I guess that you ultimately have to do stringy things at some point. But couldn't there be some kind of type-safe mechanism for this?
- arc776 10y agoMacros & templates are AST based.
- evacchi 10y agoyou can do both; you can opt-out of the type-safe mechanism and decide to just emit arbitrary code; it's a just one more tool in your belt
- Tarean 10y agoThere are basically three ways to do meta programming in nim. Simple replacement of tokens: const debug = true template log(msg: string) = if debug: stdout.writeLine(msg) You could also use other concrete types, generics and type checked or unchecked expressions instead of string. Macros are syntax tree transformations, similar to rust compiler plugins: import macros, strutils macro readCfgAndBuildSource(cfgFilename: string): typed = let inputString = slurp(cfgFilename.strVal) result = newStmtList() for line in inputString.splitLines: # Ignore empty lines if line.len < 1: continue var chunks = line.split(',') if chunks.len != 2: error("Input needs comma split values, got: " & line) let entry = quote do: const cfg`chunks[0]` = "`chunks[1]`" result.add(entry) if result.len < 1: error("Input file empty!") readCfgAndBuildSource("data.cfg") This reads a file and creates constants from it at compile time. Emit is a tad more complex. Nim is compiled to another language like c, c++ or llvm. Emit lets you emit code in the host language, mostly to wrap libraries. Don't think there is any way to make that typesafe.
- pdexter 10y agoNim is ML-inspired? How so? Anyways, it looks like this is a code emitting example? I'm guessing the average user would never use that feature. I don't now nim but this is just an assumption. So I think we can let this one pass.
- arc776 10y agoTo be fair, this is library FFI code so this is actually for interfacing with C++ rather than 'native' Nim. Probably not something you'd encounter unless you're making a library wrapper. And if you are doing that, worth mentioning too that Nim has a utility c2nim that automatically translates headers for FFI access. The first line imports the C++ std::vector type and allows you to use it in Nim. To me that seems pretty good as a one liner to import a complex type from another language. The second line is using a template to wrap the FFI call so you can use indexing operations and generic variables with the vector. The `[]=` is describing how to write to std::vector in nim using indexing, eg; "myVec[5]=123"
- lobster_johnson 10y agoThat example is complicated because it interfaces with C++ and defines a macro. Most Nim code looks nothing like that. > I don't think Nim and many other ML-inspired languages I don't think Nim is particularly ML-inspired. Nim's main point of influence is Turbo Pascal/Delphi and their deratives, which used to be obvious from all the "T" prefixes (TObject and so on, now largely or entirely gone from the language). Nim has things like ranges and enums, both of which come directly from Pascal.
- amyjess 10y agoThere's also a lot of Modula-3 in Nim, too. Which makes sense: Modula-3 is also a Pascal derivative, and there's a lot of Modula-3 in Python, which Nim borrows syntax from, too.
- lobster_johnson 10y agoThere's so much overlap between the Wirth languages that I am not surprised about that. What specifically comes from Modula-3, though? I didn't know that Python was influenced by Modula. Any examples? Keyword arguments is the only that comes up on Google.
- amyjess 10y ago> What specifically comes from Modula-3, though? Off the top of my head, the equivalency of "foo.bar(baz)" and "bar(foo, baz)" was inspired by Modula-3's object model, though Nim extends it to everything and not just classes. Also, Wikipedia tells me the pointer system comes from Modula-3. Nim's official FAQ also lists Modula-3 as the single biggest influence; I have a feeling that a lot of the Wirth-isms in Nim were borrowed from Modula-3 rather than from Pascal, even if they appeared in both languages. > I didn't know that Python was influenced by Modula. Any examples? Keyword arguments is the only that comes up on Google. Off the top of my head: - The module system. The syntax of "import foo" and "from foo import bar" were borrowed from Modula-3 verbatim, and Guido got the idea to give Python a module system in the first place because Modula-3 convinced him modules were the future. - The exception system. A lot of people don't notice the exception system because pretty much every language in the '90s also borrowed that from Modula-3 (the try-catch paradigm was invented by Modula-3), but Python hews even closer to the Modula-3 model by using the word "except" instead of "catch" and allowing for multiple except blocks attached to a single try block. - The object system is a hybrid of Modula-3 and C++; the whole idea of passing "self" as the first parameter to a method instead of having an implicit "this" was a Modula-3 thing. The official Python documentation still references it: https://docs.python.org/3/tutorial/classes.html https://docs.python.org/3/tutorial/classes.html Guido also talks about the Modula-3 influence in a few places: https://docs.python.org/3/faq/general.html#why-was-python-created-in-the-first-place https://docs.python.org/3/faq/general.html#why-was-python-cr... http://www.artima.com/intv/pythonP.html http://www.artima.com/intv/pythonP.html