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.the `*` marker means that the proc/template is "public" (not local to the module)
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)
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"
> 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.
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 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
Guido also talks about the Modula-3 influence in a few places:
https://docs.python.org/3/faq/general.html#why-was-python-cr...
I wish Andreas Rumpf were here to comment and hopefully correct me, but I believe he was formerly an ObjectPascal/Delphi programmer. The first version of the Nim compiler was written in Borland's ObjectPascal dialect (see http://nim-lang.org/docs/intern.html), which has some of the same features as Modula, but with a slightly more circuituous lineage, since it was originally based on Apple's Object Pascal, a dialect which Wirth was tangentially involved in designing. (Object Pascal predates Modula-3, too.) In that sense, some of the similarities are probably accidental or caused by cross-pollination (for example, Borland probably took the exception handling syntax from Modula). That's the problem of trying to infer lineage by looking at similarities alone.
The unified call syntax sounds like it might be lifted directly from Modula, though.
Thanks for the Python trivia, I didn't know that.
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?
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.
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.
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.