Ah, I've been struggling to build an inliner and partial evaluator for speeding up my interpreter (http://github.com/akkartik/wart#readme). Why didn't I think of just caching macro expansions?! Many thanks.
Well, from what I understand, Go has a separation between "interface" and "implementation", correct? You use this blob of code to specify the interface and this blob to implement the implementation of the interface.
In most of my examples, I showed how you can use traits like interfaces/protocols: the trait specifies traits and functions implement the behavior. But you can also use "provide" to implement the behavior directly in the trait. So my traits system blends the two together.
And you can use them as wrappers and data structs, something that I don't think you can do with interfaces in Go.
---
In addition, from what I understand, Go basically says, "if ANY type implements these functions with these signatures, it's a member of this interface."
My traits are more restrictive than that: the data type has to be tagged with a trait in order to be recognized as possessing that trait.
In other words, Go's system is a lot like Python's system: if it has these methods, it's a member of the type. Except Go also uses the function's argument and return signatures to further disambiguate, so Go avoids a lot of the problems of Python's system.
Go basically says, "if ANY type implements these functions with these signatures, it's a member of this interface."
Yes, this is I think the most innovative aspect of Go interfaces, and one of Go's best features. It's duck typing in a statically type-checked language. It avoids Java's problem of tagging classes with long lists of interfaces that they implement.
Well, from what I understand, Go has a separation between "interface" and "implementation", correct?
Given the above property there isn't really an implementation anymore. Individual types just have to implement the right functions, but that isn't really a blob of code to implement any single interface.
I spent a week thinking I should be able to crank it out with a few hours of work, but unable to actually do so. Finally I gave up and just threw the idea out there without any code, and boy am I glad I did!
Part of the problem was that hacking on wart I've forgotten that I have a mature lisp available to me.
"..for simple cases, Ruby's interpolated strings work out just as well as unhygienic macros in Arc, but if you want to do anything more complicated that actually involves inspecting/manipulating the string/block, it'll be a lot harder if not impossible."
Yeah. Another way of saying that is that packing the parsing of the AST into a macro-like feature is less powerful than exposing it to the rest of the language. This is why I don't consider string-interpolation-and-eval to be macro support.
Here are a few languages that have tried to build lisp macro support (none successfully, IMO):
Lispers will hold these up as examples that you need s-expressions to do macros 'right'. But I'm starting to question this. Is smalltalk 'homoiconic'? I think you could argue yes. And factor certainly supports a very powerful notion of quotations.
"This is why I don't consider string-interpolation-and-eval to be macro support."
Well it's not a macro anyways because `eval` runs at runtime. But it is roughly analogous to vaus in Kernel/Nulan, which in turn are a superset of (runtime) macros. Except that, in Ruby, it's a very hacky vau which is limited in power. :P
---
"Lispers will hold these up as examples that you need s-expressions to do macros 'right'."
I think it's just as I said. The more syntax you add (and especially the more complex the syntax is), the harder it is to deal with macros. That's all. S-expressions happen to be the simplest, most consistent, and readable syntax we've found, which makes it ideal for macros.
But Nulan is an example where it is possible to add syntax to a Lisp, just so long as the syntax translates easily into S-expressions underneath. Arc is another milder example of the same idea.
---
"My final evidence that the word 'homoiconic' is so fuzzy as to be useless"
I don't see how it's useless... as those pages suggest, "homoiconity" describes not a binary 1/0 but a continuum of languages. That does make it a fuzzy analog word, but a lot of words we use are like that: we humans think in fuzzy analog ways. That doesn't make it useless.
---
"But I'm starting to question this. Is smalltalk 'homoiconic'? I think you could argue yes. And factor certainly supports a very powerful notion of quotations."
I think you're worrying too much about "macros". What I care about isn't macros, but the ability to create new constructs that look and behave just like existing constructs.
If the language doesn't have any special forms (everything is a function), then the language only needs functions and not macros/vaus.
But Lisps usually do have special forms (lambda, if, etc.) and the primary way to define new special forms is with macros. Kernel/Nulan/wart achieve the same thing with vau.
Ruby's eval makes it possible to define certain constructs which would otherwise be impossible without eval. But you still can't define new things that look and act like "if", "def", etc. because the only way you can turn off evaluation in Ruby is with a block.
---
So, Ruby's string interpolation + eval is more powerful than languages like Python which don't have it, but it's still less powerful than macros/vaus in Lisp-like languages. And in languages with laziness like Haskell, you might not even need macros/vaus at all!
If Ruby had some way to plug into the parser, then it could add new syntax. But Ruby's syntax is quite complicated, so dealing with things at the parser level would probably be very hard. In any case, it's moot because Ruby doesn't let you do that, as far as I know.
Magpie does have the ability to plug new things into the parser, therefore Magpie is just as powerful as macros in Lisp. And Magpie's syntax seems simple enough to me that I think it can actually work out okay. Whether it's as easy as S-expressions or not is another story... I think the primary benefit of S-expressions is that they make macros easy, not that they make it possible.
---
I would say that Magpie is homoiconic, due to it representing its source code as a user-manipulable object, and it also has quotations which make it easy to create said objects.
That's why the word "homoiconity" is a fuzzy continuum: different languages have different abilities, and they achieve their abilities in different ways. And even two languages with very different abilities or ways of achieving those abilities can still be equivalent in power.
What I care about is the power to do things, so I'm trying not to get too hung up on one particular technique like macros. As long as it works well enough, it's fine by me, whether it's strings + eval, Magpie's quotations, Haskell's laziness, macros, vau, etc.
---
By the way, I'm not trying to argue that Ruby is homoiconic: I don't think it is. I was merely pointing out that even a non-homoiconic language with lots of complex syntax like Ruby can still get a lot of the same power that (unhygienic Arc-like) macros have. Just not all of it.
The same has been said of macros: they give you a lot of the same power that vaus have, just not all of it. Then again, there are some things that macros can do that vaus can't... so it seems that they are more like an evolutionary split in the tree: vaus don't replace macros, instead they grow alongside them in a different branch.
"Here are a few languages that have tried to build lisp macro support (none successfully, IMO):"
I dunno, Nemerle and Perl seem okay to me. Can't really speak about Dylan or Template Haskell, except to say that it seems to me the only reason Haskell needs macros is due to its restrictive type system.
Yeah, I somehow hadn't considered higher-order functions at all :/
almkglor had an interesting suggestion: view this idea in terms of pattern matching. When you see a function you see if it makes sense to apply it in the given context.
So in (map f list), the f would likely not apply to map, so it would be treated as an object.
That's an interesting idea too, and it looks like you're moving into a more fuzzy analog kind of system, not entirely unlike how JavaScript takes both operands into account with `+` so that 1 + "foo" returns "1foo"
Well, it's true that the Nuit spec intentionally ignores encoding issues, and thus a Nuit parser/serializer might need to understand encoding in addition to the Nuit spec. I don't see a problem with that.
The Arc implementation of Nuit basically just ignores encoding issues because Racket already takes care of all that. So any encoding information in the Nuit spec would have just been a nuisance.
There's already plenty of information out there about different Unicode encodings, so people can just use that if they don't have the luxury of relying on a system like Racket.
---
I see encoding as having to do with the storage and transportation of text, which is certainly important, but it's beyond the scope of Nuit.
Perhaps a Nuit serializer wants to use ASCII because the system it's communicating with doesn't support Unicode. It could then use Punycode encoding.
Or perhaps the Nuit document contains lots of Asian symbols (Japanese, Chinese, etc.) and so the serializer wants to use an encoding that is better (faster or smaller) for those languages.
Or perhaps it's transmitting over HTTP in which case it must use CR+LF line endings and will probably want to use UTF-8.
---
I'll note that Nuit also doesn't specify much about line endings. It says that the parser must convert line endings to U+000A but it doesn't say what to do when serializing.
If serializing to a file on Windows, the serializer probably wants to use CR+LF. If on Linux it would want to use LF. If transmitting over HTTP it must use CR+LF, etc.
Nuit also doesn't specify endianness, or whether a list should map to an array or a vector, or how big a byte should be, or whether the computer system is digital/analog/quantum, or or or...
Nuit shouldn't even be worrying about such things. Nuit shouldn't have to specify every tiny miniscule detail of how to accomplish things.
They are implementation details, which should be handled by the parsers/serializers on a case-by-case basis, in the way that seems best to them.
a) Anybody can flag a story, and that somehow causes spam to be flagged in automatic fashion.
b) A few users are given moderator privileges and the ability to mark stories dead or users ignored. When a story is marked dead it is visible only to the submitter. When a user is marked ignored all his stories are automatically marked dead.
I think it doesn't matter -- because newbie programmers can't yet make such judgements.
"This may be a lot of work.."
The problem isn't that it's a lot of work. Learning programming is a lot of work. The problem is that it's a lot of make-work much of the time. It's distracting the student from getting started. It's increasing the risk that (s)he'll lose interest and give up.
Forget community, forget growth rate, forget marketing. Just pick a language where you have a mentor to help you out when you get stuck. Then pick a little problem you care about, and figure out the minimum you have to study and understand to get it to work. As you gain experience, be open to learning about the internals of your tools. Don't plan to just use libraries; plan to (eventually) jump into the rabbithole, and learn how they've been built.
None of the languages you're likely to pick will be utterly without libraries. If you pick a language without the libraries to do what you want, your mentor will set you straight pretty quickly. And perhaps your initial project isn't too important; if so just switch to a different one better suited to your language.
Focusing on languages and libraries may cause you to forget that learning is an open-ended life-long process. The difference between 'learning programming' and 'learning java/lisp/blub' is the difference between an education and literacy: if you do it right you'll learn new languages and libraries easily, like a fish taking to water. But if you don't have the fundamentals you'll always program the way I swim. No libraries will save you.
Ok, well I'll still suggest that doing some research and stepping through the evaluation process can only improve your abilities. I also think that the process of researching, evaluating and spending time trying to make an informed decision would not lead to being closed minded, as you are suggesting... I think that might be a little far out there.
And while I agree that it could distract some people, I also think that picking a language with more road blocks and frustration points can do far more damage to a newbies enthusiasm/momentum than some initial research might otherwise cause.
Besides all that, IMHO, it seems to me he's looking for more guidance than what his brother already contributed, being "languages don't matter" (obviously this didn't settle his appetite to understand the options over getting started).
"..the process of researching, evaluating and spending time trying to make an informed decision would not lead to being closed minded.."
'Close minded' implies intolerance. Did I really seem to suggest that? I meant to imply ignorance. All that needs is lack of exposure (or inefficient exposure), not any conscious unwillingness to learn.
"..picking a language with more road blocks and frustration points can do far more damage to a newbies enthusiasm/momentum than some initial research might otherwise cause."
Yeah that is true. Everybody's going to eventually hit frustration points, and some positive associations at the outset can help reinforce a trajectory of persistence. But there's a lot more to the frustrations of programming than language.
Perhaps it's worth providing a blacklist of languages to avoid. I'm curious what would go on your blacklist; no modern language seems particularly egregious to my mind.
I was writing 'closed minded' thinking only in terms of not choosing to learn rather than any intolerance or stubbornness. Poor choice of words on my part - sorry about that.
I don't have a blacklist, but as a newbie, having hit the wall so many times with Arc as my first language I can't help but think I should have done some rudimentary research before I sunk the time and effort in that i did.
I still think Arc is a great first language choice, but setting the expectations prior to the investment would have limited the frustration for me. Of course even for me this was back in the day when you could hope the Arc language community might get ahead of the curve while you were learning and produce enough libraries to fill in some of the missing features like practical and robust database access. These days that would be crazy thinking, IMHO.
Sometimes getting off the ground isn't enough. I think it's better to get off the ground and get some momentum going too. Clojure would have done that for me, but at the time I believe arc was more popular / mature than Clojure.
As a note I still think Arc first then Clojure is an awesome path. With arc you can get up and running fast with a really well written tutorial. And as a bonus, because there's only a simple[1] set of features making up the core you do not have to deal with the extra complexities (such as immutability) right at the beginning. This lessens the burden. But, at the same time, I'm going to suggest that newbies treat arc like a learning language rather than something they can develop real world, deep applications with (Of course this is a general statement that can not account for each persons specific needs).
[1] simple may require a more in depth conversation here. i.e In application it may mean it's is really easy, but not actually very simple...all this is assuming you've followed Rich Hickey's 'Simple made Easy' campaign.
"I'm going to suggest that newbies treat arc like a learning language rather than something they can develop real world, deep applications with (Of course this is a general statement that can not account for each persons specific needs)."
Well, that's not entirely true... If you're talking about Arc 3.1, then of course it has a huge lack of libraries.
But Arc/Nu has access to most of Racket's libraries: for instance, "re.arc" just uses Racket's regexp support to implement regexp matching.
As another example, in an internal application I wrote in Arc, I had to parse XML. I used Racket's built-in XML parser which also has an option to use "X-Expressions" which is basically XML represented as S-expressions:
I have to say, even though I don't like Racket the language... Racket the infrastructure and libraries is top-notch. I suppose the same has been said about Java.
---
So, although I agree with you that Arc 3.1 is lacking, that's not necessarily true of forks like Anarki, ar, or Arc/Nu. And I think the only reason Arc 3.1 is lacking is because pg has been busy with non-Arc things.
That's one major benefit Clojure (and other languages) have over Arc: they're still being actively maintained.
---
I still agree with you in principle, though, that a language like Clojure, Python, or Ruby would be easier to get up and running, due to their larger community and wider availability of libraries. In particular, even though I haven't used it, Clojure looks like a very nice language, from the small bits and pieces I've seen.
I would too, even though I've come to dislike mutability. Ruby has the community, the libraries, and the features. It's also a fairly consistent and clean language overall. I'd rank it at roughly the same level as Arc, maybe a tiny bit higher.
Ruby syntax is quite consistent and clean, and its support for closures very handy. I really like it.
Clojure has a strong philosophical bias for immutability and a functional approach, but has a slightly higher overhead with its combination of Lisp and support for Java. I think it has a bright future, despite pg's view that the jvm isn't what the 100 year language will be built on. :)
"..'closed minded' thinking only in terms of not choosing to learn rather than any intolerance.."
Sorry, that was all I meant as well. Intolerance in the sense of 'intolerant of the pains required to learn programming'. There's no negative connotation to that sense, I think.
At the risk of going around in circles, I was referring to all the subconscious reasons people fail to get going with programming, rather than any conscious intolerance.
I actually wasn't thinking of arc at all. You can probably find better first languages (though having the compiler open in a split window is a unique selling point). But it doesn't seem worth optimizing beyond a point. Just pick one and keep going. The test of a first language is not whether you hate it after a while, but whether you keep programming in some language.
I'm focusing on Clojure now though I will keep an eye on Arc developments. Arc is really nice to play with but I agree that Clojure has the traction, even by the yardstick pg mentioned about what it'll take for a language to dominate (community, number of books, power of the language itself, etc.). It also has the whole Java library to support it, even though it has led to some uncomfortable syntax in some cases.
Additionally, I find Rich Hickey has given deep thought to his philosophy re programming and its challenges, and has applied it quite consistently over the years. There is a clear pattern in his approach to the development of Clojure and more recently to that of Datomic, with much of it coming out of the ideas he talked about years ago on the concept of simplicity.
"And while I agree that it could distract some people, I also think that picking a language with more road blocks and frustration points can do far more damage to a newbies enthusiasm/momentum than some initial research might otherwise cause."
That's a good point. Newbies can get turned off when things seem opaque.
"Just pick a language where you have a mentor to help you out when you get stuck."
Good point. In my experience you really need someone to open the door for you, even if only just. That's what draws you in. Once in, momentum takes care of many things, but if you don't get led in at this stage, you could give up easily. I lost a good number of years without such a mentor.
I wouldn't know what to say to a complete newbie, but you've done C++ and labview. Just keep a relatively small project in mind, pick any language, and keep at it. Persistence is everything.
If you end up going with arc, start with these links: