See, this summer I got excited about playing guitar again. I usually switch between all-guitar and all-piano every other year or so. This summer I dusted off the guitars and learned a bunch of pieces, and even composed one. I was prepping for — among other things — a multimedia blog entry. It was going to have a YouTube video, and a detailed discussion of a wacky yet powerful music programming language you've probably heard of but never used, and generally just be really cool.
And then it all came crashing down when I busted my thumbnail off. And I mean off — it broke off at least a quarter inch below where the nail and skin meet. Ick. I just accidentally jabbed my steering wheel, and that was that.
I remember reading an interview with some dude who said he had punched a shark in the nose. He said it was like punching a steering wheel. So now I know more or less what it's like to punch a shark in the nose, I guess. There's always an upside!
Anyway, that was going to be my magnum opus (literally: Op. 1) for the year, but it fell through for now. I'll have to revisit the idea next year. My thumbnail's back, but it's been at least 2 months since I touched my guitar, so I'll have to start over again.
Work has been extraordinarily busy, what with having to collect all these Nuka-Cola Quantum bottles and so on. I'm sure you can imagine. So I haven't had much time to blog lately.
But I do like to publish at least once a month, whether or not anyone actually cares. It's been about a month, or it feels that way anyway, and all I have to show for it is this box of Blamco Mac and Cheese.
So I'm cheating this month.
You know how on Halloween how you walk around in your costume holding your little bag and you say "trick or treat", and every once in a while some asshole does a trick instead of dumping half a pound of candy into your bag? And then he has to explain to all the dumbfounded and unhappy kids that "Trick or Treat" means that a trick is perfectly legal according to the semantics of logical-OR, and the kids remember that a-hole for the rest of their childhoods and avoid his house next year?
Yeah.
So I'm doing a trick this time. Hee. It's actually kind of fun when you're on the giving end.
My trick is this: in lieu of saying anything meaningful or contemporarily relevant, I'm writing about something I did over a year ago. And there isn't much to say, so this really will be short.
Ejacs
Around a year ago, I wrote a blog called Stevey's Boring Status Update, mostly in response to wild rumors that I'd been fired from Google. Not so. Not yet, anyway.
In that blog I mentioned I was working nights part-time (among other things) on a JavaScript interpreter for Emacs, written entirely in Emacs Lisp. I also said I didn't have a name for it. A commenter named Andrew Barry suggested that I should not call it Ejacs, and the name stuck.
Ejacs is a port of Narcissus. Narcissus is a JavaScript interpreter written in JavaScript, by Brendan Eich, who by pure unexpected coincidence is also the inventor of JavaScript. Narcissus is fairly small, so I thought it would be fun to port it to Emacs Lisp.
It turns out Narcissus is fundamentally incomplete. It cheats. It's that trick guy on Halloween. Narcissus has a working parser and evaluator, but for its runtime it calls JavaScript. So it's kind of like saying you're building a car by starting from scratch, using absolutely nothing except for a working car.
This meant I wound up having to write my own Ecma-262 runtime, so that the evaluator would have something to chew on. In particular, the Ecma-262 runtime consists of all the built-in properties, functions and objects: Object, Function, Array, String, Math, Date, RegExp, Boolean, Infinity, NaN, parseInt, encodeURIComponent, etc. A whole bunch of stuff.
I basically did this by reading the ECMA-262 specification and translating their algorithms into Emacs-Lisp. That spec is lousy for learning JavaScript, but it's absolutely indispensable if you're trying to implement JavaScript.
I didn't know Emacs-Lisp all that well before I started, but boy howdy, I know it now.
Emacs actually has a pretty huge runtime of its own — bigger than you would ever, ever expect given its mundane title of "text editor". Emacs has arbitrary-precision mathematics, deep Unicode support, rich Date and Calendar support, and an extensive, fairly complete operating system interface. So a lot of the porting time was just digging through Emacs documentation (also extensive) looking for the Emacs version of whatever it was I was porting. That was nice.
I had big plans for Ejacs. I was going to make it a full-featured, high-performance JavaScript interpreter, with all the Emacs internals surfaced as JavaScript native host objects, so you could write Emacs customizations using object-oriented programming. It was totally going to be the "meow" part of the cat.
And then I broke my thumbnail.
Actually, what happened was js2-mode.
js2-mode
After I got the interpreter working, I was at this crossroads. There were two big use cases: a JavaScript editing mode, or a JavaScript Emacs development mode. Both were going to be a lot of work.
It turns out you really want the editing mode first, if possible, so that when you're doing all your JavaScript programming you have a decent environment for it. So I picked the editing mode.
Unfortunately I found the Ejacs parser wasn't full-featured enough for my editing needs, since at the time I was working on my Rhino-based Rails clone and writing tons of JavaScript 1.7 code on the JVM.
I spent a little time trying to beef up the parser, then realized it would be a lot faster to just rewrite it by porting Mozilla Rhino's parser, which is (only) about 2500 lines of Java code. Ejacs is something like 12,000 lines of Emacs-Lisp code, all told, so that didn't seem like a big deal.
So I jumped in, only to find that while the parser is 2500 lines of code, the scanner is another 2000 lines of code, and there's another 500 or so lines of support code in other files. So I was really looking at porting 5000 lines of Java code.
Moreover, the parse tree Rhino builds is basically completely incompatible with the Ejacs parse tree. It was richer and more complex, and needed more complicated structures to represent it.
So after I'd ported the Rhino parse tree, what I really had was a different code base. I went ahead and finished up the editing mode, or at least enough to make it barely workable (another 5000 lines of code), and launched it. It was a surprisingly big effort.
And it left poor Ejacs lying unused in the basement.
So today, faced with nothing to write about, I figured I'd dust off Ejacs, launch it with lots of fanfare, and then you'd hardly notice that I cheated you. Right?
You're not coming to my house next year. I can tell already.
Anyway, here's the code: http://code.google.com/p/ejacs/
There's a README and a Wiki and installation instructions and stuff. I can't remember how to put the code in SVN, and I'm having trouble finding it on the code.google.com site. As soon as I figure it out I'll also make it available via SVN.
Emacs Lisp vs. JavaScript
In the interests of having something resembling original worthwhile content today, I'll do a little comparison of Emacs Lisp and JavaScript. I know a lot about both languages now, and a few folks mentioned that a comparison would be potentially interesting.
Especially since I think JavaScript is a better language.
So... the best way to compare programming languages is by analogy to cars. Lisp is a whole family of languages, and can be broken down approximately as follows:
- Scheme is an exotic sports car. Fast. Manual transmission. No radio.
- Emacs Lisp is a 1984 Subaru GL 4WD: "the car that's always in front of you."
- Common Lisp is Howl's Moving Castle.
This succinct yet completely accurate synopsis shows that all Lisps have their attractions, and yet each also has a niche. You can choose a Lisp for the busy person, a Lisp for someone without much time, or a Lisp for the dedicated hobbyist, and you'll find that no matter which one you choose, it's missing the library you need.
Emacs Lisp can get the job done. No question. It's a car, and it moves. It's better than walking. But it pretty much combines the elegance of Common Lisp with the industrial strength of Scheme, without hitting either of them, if you catch my drift.
Anyway, here's the comparison. Here's why I think JavaScript is a better language than Emacs Lisp.
Problem #1: Momentum
A recurring theme is that Elisp and JavaScript both will both exhibit a particular problem, and there are specific near-term plans to fix it in JavaScript, but no long-term plans to fix it in Elisp.
It's easier to resign yourself to a workaround when you know it's temporary. If you know the language is going to be enhanced, you can even design your code to accommodate the enhancements more easily when they appear.
People are working on improving JavaScript. It's not happening quite as fast as I'd hoped earlier this year, but it's still happening. As far as I know, Emacs Lisp is "finished" in the sense that no further evolution to the language is deemed necessary by the Emacs development team.
Problem #2: No encapsulation
Every symbol in Emacs-Lisp is in the global namespace. There is rudimentary support for hand-rolled namespaces using obarrays, but there's no equivalent to Common Lisp's
in-package, making obarrays effectively useless as a tool for code isolation.The only effective workaround for this problem is to prefix every symbol with the package name. This practice has become so entrenched in Emacs-Lisp programming that many packages (e.g.
apropos and the elp elisp profiler) rely on the convention for proper operation.The main adverse consequence of this problem in practice is program verbosity; it makes Emacs-Lisp more difficult to read and write than Common Lisp or Scheme. It can also have a non-negligible impact on performance, especially of interpreted code, as the prefix characters can approach 5% to 10% of total program size in some cases.
The problems run slightly deeper than simple verbosity. Without namespaces you have no real encapsulation facility: there is no convenient way to make a "package-private" variable or function. In practice there's little problem with program integrity; it's hard for an external package to change a "private" variable inadvertently in the presence of symbol prefixes. However, it makes it annoyingly difficult for users of the package to discern the "important" top-level configuration variables and program entry points from the unimportant ones. Elisp attempts a few conventions here, but it's a far cry from real encapsulation support.
JavaScript also lacks namespaces. They're being added in ES/Harmony, but in the meantime, browser JavaScript code typically uses the same name-prefixing practice as Emacs-Lisp.
However, JavaScript has lexical closures, which provide a mechanism for creating private names. One common encapsulation idiom in browser JavaScript is to wrap a code unit in an anonymous lambda, so that all the functions in the code unit become nested functions that close lexically over the top-level names in the anonymous lambda. This trick is nowhere near as effective in Emacs-Lisp, for several reasons:
- elisp is not lexically scoped and has no closures
- elisp nested defuns are still entered into the global namespace
- CL's
`flet'and `labels' are only weakly supported, via macros, and they frequently confuse the debugger, indenter, and other tools.
Some elisp code (e.g. much of the code in cc-engine) prefers to work around the namespace problem by using enormous functions that can be thousands of lines long, since let-bound variables are slightly better encapsulated. Even this is broken by elisp's dynamic scope:
(defun foo ()
(setq x 7))
(defun bar ()
(let ((x 6))
(foo)
x)) ; you would expect x to still be 6 here
(bar)
7 ; d'oh!
So let-bound variables in elisp can still be destroyed by your callee: a dangerous situation at best.
Emacs is basically one big program soup. There's almost no encapsulation to speak of, and it hurts.
Problem #3: No delegation
One of the big advantages to object-oriented programming is that there is both syntactic support and runtime support for automatic delegation to a "supertype". You can specialize a type and delegate some of the functionality to the base type. Call it virtual methods or prototype inheritance or whatever you like; most successful languages support some notion of automatic delegation.
Emacs Lisp is a lot like ANSI C: it gives you arrays, structs and functions. You don't get pointers, but you do get garbage collection and good support for linked lists, so it's roughly a wash.
For any sufficiently large program, you need delegation. In Ejacs I wound up having to implement my own virtual method tables, because JavaScript objects inherit from
Object (and in some cases, Function, which inherits from Object).Writing your own virtual method dispatch is just not something you should have to do in 2008.
Problem #4: Properties
I wrote about this at length in a recent blog post, The Universal Design Pattern. JavaScript is fundamentally a properties-based language, and it's really nice to be able to just slap named properties on things when you need a place to store data.
Emacs Lisp only offers properties in the form of simple plists – linked lists where the odd entries are names and the even entries are values. Symbols have plists, and symbols operate a little bit like very lightweight Java classes (in that they're in the global namespace), but that only gets you so far. If you want the full JavaScript implementation of the Properties Pattern, you'll have to write a lot of code.
And so I did. Your implementation choice for object property lists has a huge impact on runtime performance. Emacs has hashtables, but they're heavyweight: if you try to instantiate thousands of them it slows Emacs to a crawl. So they're no good for the default
Object property list. Emacs also has associative arrays (alists), but their performance is O(n), making them no good for objects with more than maybe 30 or 40 properties.I wound up writing a hybrid model, where the storage starts with lightweight alists, and as you add properties to an object instance, it crosses a threshold (I set it to 50, which seemed to be about right from profiling), it copies the properties into a hashtable. This had a dramatic increase in performance, but it was a lot of work.
I experimented with using a splay tree. I implemented Sleater and Tarjan's splay tree algorithm in elisp; Ejacs comes with a standalone
splay-tree.el that you can use in your programs if you like. I was hoping that its LRU cache-like properties would help, but I never found a use case where it was faster than my alist/hashtable hybrid, so it's not currently used for anything.And then in the end, after I was done with my implementation, it was a library (at least from the Emacs-Lisp side of the house). It wasn't an object system for Lisp. It's only really usable inside the JavaScript interpreter, where it has syntactic support.
You really want syntactic support. Sure, people have ported subsets of CLOS to Emacs Lisp, but I've always found them a bit clunky. And even in CLOS it's hard to implement the Properties Pattern. You don't get it by default. CLOS has lots of support for compile-time slots and virtual dispatch, but very little support for dynamic properties. It's not terribly hard to build in, but that's my point: for something that fundamental, you don't want to have to build it.
Problem #5: No polymorphic
toStringOne of the great strengths of JavaScript is the
toSource extension. I don't know if they support it over in IE-land; I haven't been a tourist there in a very long time. But in real versions of JavaScript, every object can serialize itself to source, which can then be eval'ed back to construct the original object.This is even true for functions! A function in JavaScript can print its own source code. This is an amazingly powerful feature.
In Emacs Lisp, some objects have first-class print representations. Lists and vectors do, for instance:
(let ((my-list '()))
(push 1 my-list)
(push 2 my-list)
(push 3 my-list)
my-list)
(3 2 1)
(let ((v (make-vector 3 nil)))
(aset v 0 1)
(aset v 1 2)
(aset v 2 "three")
v)
[1 2 "three"]
But in Emacs Lisp, many built-in types (notably hashtables and functions) do NOT have a way to serialize back as source code. This is a serious omission.
Also, trying to print a sufficiently large tree made entirely of
defstructs will crash Emacs, which caused me a lot of grief until I migrated my parse tree to use a mixture of defstructs and lists. Note that simply typing the name of a defstruct, or passing over it ephemerally in the debugger, will cause Emacs to try to print it, and crash. Fun.The problem of polymorphic debug-printing (or text-serialization) is, I think, a byproduct of Emacs not being object-oriented. If you want a debug dump of a data structure, you write a function to do it. But Emacs provides a half-assed solution: it debug-prints lists very nicely, even detecting cycles and using the #-syntax for representing graph structures (as does SpiderMonkey/JavaScript). But it has no useful debugging representation for hashtables, functions, buffers or other built-in structures, and there's no way to install your own custom printer so that the debugger and other subsystems will use it.
So it sucks. Printing data structures in Emacs just sucks.
The situation in Ecma-262-compliant JavaScript really isn't that much better, although you can at least install your own
toString on the built-ins. But any competent "server-side" JavaScript implementation (i.e. one designed for writing real apps, rather than securely scripting browser pages) has a way to define your own non-enumerable properties, so you can usually override the default behavior for things like toString and toSource.And all else being equal, at least JavaScript functions print themselves.
Emacs advantages: Macros and S-expressions
Pound for pound, Emacs Lisp seems roughly as expressive as JavaScript or Java for writing everyday code. It shouldn't be that way. Emacs Lisp ought to be more succinct because it's Lisp, but it's incredibly verbose because of the namespace problem, and it's also verbose to the extent that you want to use the properties pattern without worrying about alist or hashtable performance.
Elisp does have a few places where it shines, though. One of them is the
cl (Common Lisp emulation) package, which provides a whole bunch of goodies that make Elisp actually usable for real work. Defstruct and the loop macro are especially noteworthy standouts.Some programmers are still operating under the (ancient? legacy?) assumption that the
cl package is somehow deprecated or distasteful or something. They're just being silly; don't listen to them. Practicality should be the ONLY consideration.The
cl package wouldn't have been possible without macros. JavaScript has no macros, so even though it has better support for lambdas, closures, and even (in some versions) continuations, there are still copy/paste compression problems you can't solve in JavaScript.Emacs Lisp has
defmacro, which makes up for a LOT of its deficiencies. However, it really only has one flavor. Ideally, at the very least, it should support reader macros. The Emacs documentation says they were left out because they felt it wasn't worth it. Who are they to make the call? It's the users who need them. Implementer convenience is a pretty lame metric for deciding whether to support a feature, especially after 20 years of people asking for it.Elisp is s-expression based, which is a mixed bag. It has some advantages, no question. However, it fares poorly in two very common domains: object property access, and algebraic expressions.
JavaScript is NOT s-expression based (or it wouldn't be a successful language, many would argue), but it does offer some of the benefits of s-expressions. JSON is one such benefit. JavaScript's declarative object literals (or as a Lisp person would say, "syntax for hashes") and arrays provide a powerful mechanism for designing and walking your own declarative data structures.
JavaScript also has all the usual (which is to say, expected) support for algebraic operators. And unlike Java, JavaScript even got the precedence right, so it's not full of redundant parentheses.
Overall Comparison
In the end, it comes down to personal choice. I've now written at least 30,000 lines of serious code in both Emacs Lisp and JavaScript, which pales next to the 750,000 or so lines of Java I've crapped out, and doesn't even compare to the amount of C, Python, assembly language or other stuff I've written.
But 30,000 lines is a pretty good hunk of code for getting to know a language. Especially if you're writing an interpreter for one language in another language: you wind up knowing both better than you ever wanted to know them.
And I prefer JavaScript over Emacs Lisp.
That said, I suspect I would probably prefer Clojure over Rhino, if I ever get a chance to sit down with the durn thing and use it, so it's not so much "JavaScript vs. Lisp" as it is vs. Emacs Lisp.
I would love to see Emacs Lisp get reader macros, closures, some namespace support, and the ability to install your own print functions. This reasonably small set of features would be a huge step in usability.
However, for the nonce I'm focusing on JavaScript. I've found that JavaScript is a language that smart people like. It's weird, but I keep meeting really really smart people, folks who (unlike me) are actually intelligent, and they like JavaScript. They're always a little defensive about it, and almost a little embarrassed to admit it. But they think of it as an elegant, powerful, slightly flawed but quite enjoyable little language.
I tell ya: if you're a programming language, it's a very good thing to have smart people liking you.
It doesn't make me smart, but I kinda like it too. Even though there's (still) a lot of hype these days about Java, and people tootling on about how Java's going to be the next big Web language... I just don't see it happening. There are too many smart people out there who like JavaScript.
So enjoy the interpreter. Ejacs is just a toy, but I think it also shows a kind of promise. Scripting Emacs using JavaScript (if anyone ever actually implements it) could be really interesting. It could open up the world's most powerful, advanced editing environment to millions of people. Neat.
In the meantime, it doesn't actually do squat except interpret EcmaScript in a little isolated console, so don't get your hopes up.
Reminder — here's the Ejacs URL: http://code.google.com/p/ejacs - enjoy!
And with that, I'm off to find some Nuka-Cola Quantum. I just wish those bastards hadn't capped me at level 20.


79 comments:
I have absolutely no idea what you're talking about but Ejacs is the best name for a software package that I've heard in a long time. Long ago they taught in marketing 101 that the ideal product name should contain a promise - and what better promise is there to make?
You are a madman! Awesome. btw: js2-mode rules. Thanks,
David
Seems like it would be easier to turn firefox into an editor.
Yay! Reverse psychology wins again!
And they said I would never amount to anything...
The name of the project sounds quite naughty; I'm not a fan of it, but it is undeniably catchy. It reminds me of an idea a friend once had: a graphical editor custom tailored to a problem he was trying to solve. He named it SPOOGE (Special-Purpose Object-Oriented Graphics Editor).
Needless to say, it didn't get very far.
I also got quite far writing a javascript interpreter in javascript a while ago (or at least a reasonable subset - eg leaving out stuff like the 'with' statement).
The parser/compiler converted JS source into byte codes, for which there was a separate VM written in JS.
And then I wrote the VM in java. And then in C++.
Then I saw some butterflies...
Actually, at this point I realized there was no real commercial driver for this stuff and let it lapse.
But it was also a really good way to understand some of the low level behavior of the language.
Unfortunately this involved getting a deep understanding of the == operator. And thus a desire to punch people.
Do you really mean it when saying "But it pretty much combines the elegance of Common Lisp
with the industrial strength of Scheme", or the opposite, i.e., "But it pretty much combines the elegance of Scheme with the industrial strength of Common Lisp
"?
Maybe I am just dumb, but I always think Scheme is THE more elegant Lisp.
an0 said...
Do you really mean it when saying "But it pretty much combines the elegance of Common Lisp with the industrial strength of Scheme"
Yes, an0, he probably does mean it.
Scheme is elegant.
Common Lisp is industrial.
Emacs Lisp is not elegant, and not industrial.
Looking at the list of problems I noticed that the crown jewel of object-orientation - that is: override-able methods - is not explicitly mentioned (It is just hinted at occasionally).
I think this no coincidence: Success of OO comes from other factors (e.g.: it helps in organizing the code, simplifies expressions, etc.).
I vaguely remember Steve saying something along these lines it in one of his earlier posts. I must admit I also believe in this (implicit) sentiment.
@ano You don't get his drift.
A little bird told me that Elisp *is* actually being worked on; apparently it's going to grow lexical scoping and coroutines in the foreseeable future. Can't remember if there were plans for packages now. And that is disregarding all the smaller and more trivial fixes it regularly gets.
So, while it doesn't make Elisp suck any less at the moment, it does take away the "JS at least is being worked on" argument. And JS has a fair share of stupid crap going about it too, starting with stupidly incoherent implementations (which improves over time, but still) and ending with it being a Lisp, except with syntax and consequently no macros.
Nice article.
I think there's another way out for Elisp, by the way -- compile it to a different target than the current Emacs runtime. I know it sounds silly in 2008, but Guile might be that runtime. It gives you modules and pthreads, standard SRFI libraries, and possibility for much more optimization (including native-code JIT).
Check the guile-devel archives for info.
Verily.
I'm hoping that Bethesda will release modding tools soon. The -few- quest glitches and unkillable NPC's are annoying.
Thanks, Steve. I love interactive shells, they make me smile.
BTW, David Notkin has an immense beard. Puts my whiskers to shame!
Mark Tucker: I always enjoy seeing a reference to Why Microsoft can Blow-Off with C# here.
Almost as much as I loved the characterization of Common Lisp as "Howl's Moving Castle". I'm still laughing at that.
(Scheme isn't actually an exotic sports car. Connection Machine Lisp is the exotic sports car. As someone else I was talking to mentioned, it has a peaky, but powerful engine and a very notchy tranny that prevents you from actually using it.)
Steve, could you please tell how long it took for you to implement the ECMA spec?
I've been doing some Clojure hacking lately...and yes, you *will* like it. :)
Stu Halloway has a beta Clojure book you can pick up here:
http://www.pragprog.com/titles/shcloj/programming-clojure
Huh. I started this a while back too but don't seem to have nearly as much determination as you had.
I took an entirely different tack though. I wrote a bison grammar with elisp actions and then post-processed the bison parser into a table-based elisp parser.
I wanted to hook this into emacs-w3 to interpret javascript code on web pages so things like onclick="this.form.submit()" would work.
I had hoped if I got the interpreter basically working others would step in and implement the DOM and basic language objects. But, uh, that never happened.
Anyways, if you want to check out another attempt at the same thing look at:
http://freshmeat.net/projects/ebison/
I want the reciprocal, emacs in javascript (or pehaps java) so I can run it in a web browser or an Andriod cell phone.
Then again, you can just install Debian on a jailbroken android phone, so the idea may be kinda irrelivant soon.
I'm wondering if this javascript lisp implementation will run in it...
http://joeganley.com/code/jslisp.html
Common Lisp == Howl's Moving Castle is TOTALLY spot on. Perfect. I assume you laughed for hours when you came up with that one.
What I really want is some sort of interface between Emacs and the JVM, so we do less porting and more linking
You embedded Javascript into EMACS? Has nobody heard of Lua? :(
Mathrick is right: lexical scope has been implemented in Emacs (the lexbind branch) and is scheduled to be merged into the trunk after 23 is released, which is a few months away. Once that's in place, adding concurrency features is the next step, something that I don't think Javascript is currently targeting.
Also: elisp doesn't require an explicit "return", the requirement of which is full of fail.
I'm so happy to hear that are other people out there who like Javascript.
Emacs is basically one big program soup.
Funny thing is, so is a modern web page. HTML, CSS, JavaScript--toss into a pot and stir with a Greasemonkey script. Makes you wonder if these platforms succeed so brilliantly in spite of the tangle or because of it.
I imagine the post you hinted at writing was about Max/MSP. As a musician and a not-even-good-enough-to-call-myself-a-hobbyist programmer, I'd love to hear your take on it.
I broke my guitar thumbnail once bowling, and it hurt like hell.
an0: you missed the joke.
seshagiri: um, maybe 200 hours? It's just a guess. I didn't really pay very close attention.
mathrick: very cool! Language improvements == awesome. Closures == double awesome.
phil: concurrency, eh? Rhino has continuations _and_ threads, and I believe SpiderMonkey also supports at least one form of concurrency in the "trusted mode" you use for extensions and plugins. So yes, JavaScript has concurrency. Just not in a browser pages. Would be unbelievably awesome to see any kind of concurrency support in Emacs.
Brendan Eich says he's been thinking about concurrency and hygienic macros for a future version of JavaScript. I think they have to get over the hump of classes and optional type annotations first, though. Sounds like they're getting close.
Agree that requiring return is full of fail. JavaScript 1.8 addresses it partially with "function closures", which are single-expression lambdas that don't require the return keyword. Example:
var square = function(x) x * x;
In general, void statements and functions are a cosmically stupid idea.
You rock man!
By the way, I am still waiting for "A programmer's view of the Universe, part 2".
When it's coming up?
FYI: I know where you live!
I hpoe you won't mind some anti-JS venting, Steve. I respect your opinion but these pro-JS opinion pieces irritate me, given the amount of suffering that the JavaScript meme has caused me personally.
I certainly wouldn't defend emacs-lisp as any kind of bastion of good design, but it does contain several workarounds for the problems you're describing. Clearly, you've heard of cl-macs. Haven't you used lexical-let? You can have closures in emacs-lisp if you want them. Sure, the default behavior is terrible, but you can program in a style that works (i.e. has lexical closures and encapsulation) if you want.
This is exactly the same situation as JavaScript, as far as I'm concerned. Sure, JS has lexical scoping, but the default behavior of assignment is to set a global variable, I'm sorry, "property of the 'window' object".
Let's also not forget that elisp's library mechanism is cruddy ("require" needs no enumeration of its deficiencies) but at least it's somewhat workable. Let's compare it to JavaScript's ... oh right! JavaScript has no support for libraries because it isn't a programming language, it's a macro syntax for validating your FORM tags in Netscape 2.0.
In summary: elisp is a terrible language with the tools to make it a reasonable language. JavaScript is a prison planet from which there is no escape, if you want to write programs that run in the popular runtime, i.e. "the" browser (as if there were only one, or even only a dozen, that you needed to care about).
Dear Steve,
Thanks for your blog, a most enjoyable reading of mine nowadays.
Struggling in the Greap Elisp Swamp, I stumbled on symbol-function
Would that fit your bill for a useful debugging representation for functions in ELisp ?
Usage example:
(symbol-function 'foo)
=> (lambda nil (setq x 7))
Al.
symbol-function is fine if it's not byte-compiled. In JavaScript, the byte-compiler remembers a token stream for the function that permits the source code to be printed back. If the elisp byte-compiler did this it would be a big improvement.
Hashes still need a print representation, and defstructs are just a mess, what with the crashing.
It sounds like some of this stuff is gradually getting fixed, though, which is nice.
Stevey: could you indulge yourself and share with us a few more car analogies?
Interesting about Scheme: makes me wonder why there's no standard Scheme Radio out there that most users just agree on installing right after you drive it off the lot.
Also, you're makin' me want to watch more anime. :)
Anyone care to explain the Howl's Castle reference? Not sure I get it. Thanks.
Hi Steve,
thanks for your blog and this post.
every post wants me to improve myself and share more with the world. Thanks.
"Anyone care to explain the Howl's Castle reference? Not sure I get it. Thanks."
+1. I don't understand either :-(
BR,
~A
The Howl's Moving Castle comparison is the iridescent glowing jewel of humor in this particular post, IMHO. It refers to the eponymous Miyazaki film in which a wizard of sorts roams the countryside in a gigantic castle capable of walking about on mechanical legs. The comparison is with Common Lisp's "don't leave anything out" design.
Gavin, thanks. After googling around a bit and finding some images of the castle, I think I get it now.
Steve said: "I would love to see Emacs Lisp get reader macros, closures, some namespace support, and the ability to install your own print functions. This reasonably small set of features would be a huge step in usability."
So, what would it take to do those things? At least some of the folks at the Emacs developers mailing list read your blog. Maybe you've started something.
Most fantastic!
I thoroughly enjoyed reading this blog article. I find this blog best among all your blog essays i've read. (perhaps about 15 of them over the past year or 2)
I love emacs lisp! and i like javascript (not that much expert of it).
i enjoyed reading every word you gave about these languages.
Yeah, so much needs to be improved in emacs lisp. (and so obstinate are the emacs developers)
Lastly, thank you for Ejacs! I'm downloading it now, and sure will be having fun with it. I think the name is catchy too.
-----------------------
among your elisp criticism, i whole heartedly agree about the no namespace problem.
... (i thought i'd go over your criticism now and list my impressions on them)...
in your section “Problem #3: No delegation”. I don't quite understand what is meant, or the word delegation in the context of programing. I'll be doing some web searching readup on this now... if you do happen to edit this, perhaps in preparation for print publication down the road ... more detail or concret example would be great.
In your “Problem #4: Properties” section... i sorta understand what you mean but concrete example would be great. I don't know what splay-tree is. I'll be reading up.
On your “Problem #5: No polymorphic toString” section... i see what you are saying. For my own elisp experience, i didn't find this a problem. On the other hand, i thougth this problem is much severe in compiled langs, such as Java, C.
(Note: my elisp coding, and life time code production in general, is perhaps just 10% of your output. (if i recall correctly, i'm few years older than you though... or was it the same?...))
in my own elisp experience, i think elisp problem in order most severe to less severe, are:
• no namespace.
• lack of threads. e.g. typically you wait for emacs to finish something before it'll unfreeze.
• regex toothpick syndrom. Its regex should have its own string syntax, not embedded as string. I do a lot text processing. Even simple regex become unreadible in emacs.
• Lack of named parameters.
• lack of lexical scoping. I did not thought this is a practical problem, but now reading your article, the fact that emacs lack a namespace, i changed my mind. :D Yeah, i guess lexical scoping is critical when you write large programs.
... in your essay you mentioned elisp's lack of reader macro, and also highly praised elisp macro. In my own programing experience (mostly geometry visualization and web app backend), i never find any utility of lisp macro, and thought it is pretty much overrated by zealous lispers or lisper wannabe who came from procedural lang background just because it's something they've never seen.
Note that, lisp macro can be considered as crude beginning of term rewriting system/langs. In lisp communities, you see them get dizzy with macros all day, but in Mathematica, just about every line of code is macro a la lisp, because the lang is so-called a term rewriting system, with extensive pattern matching facilities.
... it would be great if you can give some concrete examples of how you used elisp macro. (i'll be checking it out in ejacs)
some other common criticism of elisp is lack of tail recursion, lack of continuation. I am not absolutely sure (don't fully understand the latter), but i tend to think these having little practical benefits.
Again, great article and thanks for ejacs.
Xah
∑ http://xahlee.org/
☄
I've been working on a homoiconic JavaScript syntax for madmen like you. Basically all you get now is hairy syntax, but that gets you macros for free. Not real macros though. And it doesn't have lambdas. But I'm still sorting that out. It would've been easier if JavaScript had symbols, but I think I'll be able to hack around it somehow.
Details at http://timcooijmans.wordpress.com/2008/11/26/if-you-wanna-taste-some-madness-unq/
Web Art Sense a web design company is here for a purpose to make art and design of your imagination alive and real on the web platform. After several months of hunting of the best talent and struggling for the name of their design company they finally reached a vertical which engages their vision of togetherness. The best talented people in web designs have joined hands to compete and provide innovative, unique concepts to users/clients all across the globe. Web Art Sense is not any design company; they take real care of having your brands be presented that invokes your revelation to others who see it.
Web Art Sense has their sales offices in London, New Jersey and New Delhi are heading towards marketing themselves to main continents of Europe, Australia and America. Web art sense already has ground foundation and is providing web based design development and SEO Services in countries like USA, UK, Australia and Italy. Web Art Sense has been growing above hundred percent every financial year since its foundation.
Web Design Company
An ideal Web Design company must completely understand the needs and objectives of the company, so that it can reflect upon the ideologies of the company onto the customer. Even the minutest of the details must be paid attention in order to achieve maximum results. Entrust your work to a company who as dedicated as you are in glorifying your business.
Web Design Company
Have you looked at JaM? You CAN have macros in JavaScript. http://blog.n01se.net/?p=8
Hello,
A humble request...
Do you, by any chance, happen to know who Secret Dubai (the blogger: secretdubai.blogspot.com) is?
http://whoissecretdubai.blogspot.com/
Stevey I can't read your blog while I'm working it takes too much time. While a great read I feel kinda guilty since I'm not really working. Would you consider odiogo.com or perhaps getting Donald Sutherland to read it for us? One these guys would do I guess... http://www.collegehumor.com/video:1633395
Don't know what style of music you're playing but couldn't you have played your guitar with a pick? Or super-glued a pick onto your thumbnail or used this: http://www.alaskapik.com/?
Just wondering.
concurrency in emacs is more important than it sounds. the scope of emacs network applications has been severely limited because emacs is a cooperative multitasking OS — if wanderlust or w3 hang waiting for a server response, the whole OS hangs with them (thus w3m-el — it's not that C is faster, but that you can call external apps in the background, but not internal apps!)
once emacs is true multitasking I expect lots of new applications to bloom.
ネットショップ 構築
Post Jobs on India's No.1 jobsite
http://www.back2office.com
Post your resume and find your dream job Now !
Search Jobs Post Jobs on India's Premium Jobsite
Search Professionals
India's growing job site.Jobs available in sectors like Accounting,
Marketing,IT,Engineering,Finance,BPO/Call Centers,Bio Technology,
Banks,Adminstration,HR/IR/MR,Media,Sales,Security,
Business Mgmt.,Retails,Hotels & Others.
Find Jobs In India,UK,USA,Middle East.
Thanks ur information
it very useful
web design company, web designer,
web design India,website design,web design
nice post
Small business website design
funny vedio ,online games
see this site u really enjoy and click my advertisement ,
it yours friend request
i like your blog ....
Thank u r information
its very useful
website design New York City, web designer nyc, web site design, web design
PLEAAASE DO IT !
emacs in js would be SOOO MUCH FUCKING GREAT !
Pleaaaaase !
thanks for this information it helps me in website design
WoW shares many wow gold of its features with previously launched games. Essentially, you battle with Cheapest wow gold monsters and traverse the countryside, by yourself or as a buy cheap wow gold team, find challenging tasks, and go on to higher Cheap Wow Gold levels as you gain skill and experience. In the course of your journey, you will be gaining new powers that are increased as your skill rating goes up. All the same, in terms of its features and quality, that is a ture stroy for this.WoW is far ahead of all other games of the genre the wow power leveling game undoubtedly is in a league of its own and cheapest wow gold playing it is another experience altogether.
Even though WoW is a wow gold cheap rather complicated game, the controls and interface are done in buy warhammer gold such a way that you don't feel the complexity. A good feature of the game is that it buy wow items does not put off people with lengthy manuals. The instructions cannot be simpler and the pop up tips can help you start playing the game World Of Warcraft Gold immediately. If on the other hand, you need a detailed manual, the instructions are there for you to access. Buy wow gold in this site,good for you ,WoW Gold, BUY WOW GOLD.
免費看妹妹 免費看無碼電影 免費看視訊 免費看視訊辣妹 免費看模特兒 免費美女視頻聊天 免費美女視頻聊天室 免費美女寫真 免費美女影音視訊 免費美女線上電影直播 免費美眉即時通視訊 免費美眉視訊網 免費美國大聯盟線上直播 免費美國棒球線上直播 免費美國視訊聊天室 免費美國職棒線上直播 免費音樂下載 免費音樂試聽 免費桌布下載 免費現場連線 免費現場影音 免費聊天交友 免費聊天室入口 免費脫衣表演 視訊 美眉 免費看妹妹 模特兒 免費視訊聊天 msn視訊美女 即時通視訊交友 ut聊天室 免費援助交際視訊聊天室 免費棒球線上直播 免費短片動畫試看 免費短片試看區 免費短片線上直播 免費紫微命盤 免費視訊 免費視訊入口 免費視訊交友 免費視訊交友聊天室 免費視訊秀 免費視訊美女 免費視訊美女聊天 免費視訊美女短片寫真 免費視訊美女網 免費視訊美女影音電視 免費視訊美女影音觀 免費視訊美女影音觀賞 免費視訊美眉 免費視訊聊天 免費視訊聊天室 免費視訊聊天室入口 免費視訊聊天室內 免費視訊聊天網 免費視訊辣妹 免費視訊辣妹秀 免費視訊辣妹聊天室 免費視訊辣妹短片 免費視訊播放軟體下載 免費視訊贈點 免費視頻演出 免費視聽音樂 免費視聽音樂網 免費黃色電影觀看 免費黑澀會美眉遊戲 免費試看下載成人片 免費試看美腿短片 免費試看短片A383 免費試看短片貼片 免費試看短片論壇 免費試看短片觀賞 免費試看義母短片 免費試看影片直播 免費遊戲 免費電話交友 免費漫畫 免費算命 免費網路電視線上直播 視訊 美眉 免費看妹妹 模特兒 免費視訊聊天 msn視訊美女 即時通視訊交友 ut聊天室 免費辣妹秀視訊聊天 免費辣妹視訊聊天 免費辣妹視訊聊天網 免費辣妹視訊網 免費辣妹演出 免費辣妹影檔 免費噴血影片 免費影片下載 免費影片下載區 免費影片下載網 免費影片分享 免費影片直播 免費影片線上直播 免費影音視訊聊天室 免費線上卡通直播
I think you are just waiting for events to happen and I can tell you now that this is is not the best way forward, Buy cheap WOW gold here.
I have seen people before go down this path and my experience shows me that this is not at all the way to go. Fast deilvery here.
I can even go so far as to say that some people I have tried to help who have lived through similar Transits (but let us be clear here Isis, the Transit you will experience is very rare and very unusually powerful and this is why I insist so much on warning you about it) chose to sit back and wait and all that happened it that they missed out on all of the chances and opportunties which looked so sure to benefit them! WOW gold sale
希望大家都會非常非常幸福~「朵朵小語‧優美的眷戀在這個世界上,最重要的一件事,就是好好愛自己。好好愛自己,你的眼睛才能看見天空的美麗,耳朵才能聽見山水的清音。好好愛自己,你才能體會所有美好的東西,所有的文字與音符才能像清泉一樣注入你的心靈。好好愛自己,你才有愛人的能力,也才有讓別人愛上你的魅力。而愛自己的第一步,就是切斷讓自己覺得黏膩的過去,以無沾無滯的輕快心情,大步走向前去。愛自己的第二步,則是隨時保持孩子般的好奇,願意接受未知的指引;也隨時可以拋卻不再需要的行囊,一路雲淡風輕。親愛的,你是天地之間獨一無二的旅人,在陽光與月光的交替之中瀟灑獨行。
runescape money
runescape gold
runescape money
runescape gold
Thats a very interesting post. I have been inspired. Thanks. Web Designer
網頁設計,情趣用品店,情趣用品專賣網
A片,色情A片,免費A片,成人影片,色情影片,a片免費看,情色貼圖,情色文學,情色小說,色情小說
AV,AV女優
辣妹視訊,美女視訊,視訊交友網,視訊聊天室,視訊交友,視訊美女,免費視訊,免費視訊聊天,視訊交友90739,免費視訊聊天室,成人聊天室,視訊聊天,視訊交友aooyy
哈啦聊天室,辣妺視訊,A片,色情A片,視訊,080視訊聊天室,視訊美女34c,視訊情人高雄網,視訊交友高雄網,0204貼圖區,sex520免費影片,情色貼圖,視訊ukiss
EO対策 (or come grinding engine optimization) is to rewrite the web page to appear higher in search results for a particular search engine. Its technology. Also known as search engine optimization. The English "Search Engine Optimization" to take initial measures which are known as the SEO. Search engine optimization has become a target, Google often. The foreign (especially American) by the high market share in Google. In Japan, Yahoo! For many users of the search, Yahoo! Is focused search measures.
It was not long cheap wow goldbefore some one knocked at wow gold for salethe house-door and called, open the door, dear children, your mother is here, and wow gold cheap has brought something back with her for each of you. But the little cheapest wow goldkids knew that it was the wolf, by the rough voice. We will fastgg not open the door, cried they, you are not our mother. She has a soft, pleasant voice, but your voice is rough, you are the wolf.
Then the wolf went World Of Warcraft Goldaway to a shopkeeper and bought himself a great lump of chalk, ate this and made mmogap his voice soft with it. The he came back, knocked at the door of the house, and igsky called, open the door, dear children, your mother is here and Cheapest Wow Goldhas brought something back with her for each of you.
QuestMonk MMORPG Services: Cheap runescape money,runescape gold,Buy runescape gold
EVE Money online,EQ2 Plat,EQ2 Gold, Anarchy Online ArchLord Dofus Hero online ...
Had you looked to Semantic package (from CEDET) that make process of parsing writing much easier?
Does the emacs lose alot of its ablitiy because of its OS?
Free DSiFree PSPFree PS3free console gamesconsole games free
wholesale jewelryhandmade jewelryjewelry wholesalefashion jewelrycostume jewelrywholesale costume jewelry wholesale fashion jewelrywholesale pearlwholesale crystaldiscount jewelrycheap jewelrywholesale gemstonewholesale swarovski crystalwholesale shellwholesale coralwholesale turquoisechina jewelry wholesalerwholesale china jewelrywholesale handmade jewelryhandcrafted jewelrywholesale jewellery
Navy sniperswow goldfatally shotwow goldthree pirateswow goldholding an Americanwow goldcargo-shipwow goldwow goldcaptain
Navy sniperswow goldfatally shotwow goldthree pirateswow goldholding an Americanwow goldcargo-shipwow goldwow goldcaptain
看房子,買房子,建商自售,自售,台北新成屋,台北豪宅,新成屋,豪宅,美髮儀器,美髮,儀器,髮型,EMBA,MBA,學位,EMBA,專業認證,認證課程,博士學位,DBA,PHD,在職進修,碩士學位,推廣教育,DBA,進修課程,碩士學位,網路廣告,關鍵字廣告,關鍵字,課程介紹,學分班,文憑,牛樟芝,段木,牛樟菇,日式料理, 台北居酒屋,日本料理,結婚,婚宴場地,推車飲茶,港式點心,尾牙春酒,台北住宿,國內訂房,台北HOTEL,台北婚宴,飯店優惠,台北結婚,場地,住宿,訂房,HOTEL,飯店,造型系列,學位,SEO,婚宴,捷運,學區,美髮,儀器,髮型,看房子,買房子,建商自售,自售,房子,捷運,學區,台北新成屋,台北豪宅,新成屋,豪宅,學位,碩士學位,進修,在職進修, 課程,教育,學位,證照,mba,文憑,學分班,台北住宿,國內訂房,台北HOTEL,台北婚宴,飯店優惠,住宿,訂房,HOTEL,飯店,婚宴,台北住宿,國內訂房,台北HOTEL,台北婚宴,飯店優惠,住宿,訂房,HOTEL,飯店,婚宴,台北住宿,國內訂房,台北HOTEL,台北婚宴,飯店優惠,住宿,訂房,HOTEL,飯店,婚宴,結婚,婚宴場地,推車飲茶,港式點心,尾牙春酒,台北結婚,場地,結婚,場地,推車飲茶,港式點心,尾牙春酒,台北結婚,婚宴場地,結婚,婚宴場地,推車飲茶,港式點心,尾牙春酒,台北結婚,場地,居酒屋,燒烤,美髮,儀器,髮型,美髮,儀器,髮型,美髮,儀器,髮型,美髮,儀器,髮型,小套房,小套房,進修,在職進修,留學,證照,MBA,EMBA,留學,MBA,EMBA,留學,進修,在職進修,牛樟芝,段木,牛樟菇,關鍵字排名,網路行銷,PMP,在職專班,研究所在職專班,碩士在職專班,PMP,證照,在職專班,研究所在職專班,碩士在職專班,SEO,廣告,關鍵字,關鍵字排名,網路行銷,網頁設計,網站設計,網站排名,搜尋引擎,網路廣告,SEO,廣告,關鍵字,關鍵字排名,網路行銷,網頁設計,網站設計,網站排名,搜尋引擎,網路廣告,SEO,廣告,關鍵字,關鍵字排名,網路行銷,網頁設計,網站設計,網站排名,搜尋引擎,網路廣告,SEO,廣告,關鍵字,關鍵字排名,網路行銷,網頁設計,網站設計,網站排名,搜尋引擎,網路廣告,EMBA,MBA,PMP,在職進修,專案管理,出國留學,EMBA,MBA,PMP,在職進修,專案管理,出國留學,EMBA,MBA,PMP,在職進修,專案管理,出國留學,婚宴,婚宴,婚宴,婚宴,漢高資訊,漢高資訊,比利時,比利時聯合商學院,宜蘭民宿,台東民宿,澎湖民宿,墾丁民宿,花蓮民宿,SEO,找工作,汽車旅館,阿里山,日月潭,阿里山民宿,東森購物,momo購物台,pc home購物,購物漢高資訊,漢高資訊,在職進修,漢高資訊,在職進修,住宿,住宿,整形,造型,室內設計,室內設計,漢高資訊,在職進修,漢高資訊,在職進修,住宿,美容,室內設計,在職進修,羅志祥,周杰倫,五月天,住宿,住宿,整形,整形,室內設計,室內設計,比利時聯合商學院,在職進修,比利時聯合商學院,在職進修,漢高資訊,找工作,找工作,找工作,找工作,找工作,蔡依林,林志玲
Weekends to peopleig2tmean that they can have a two-day wowgold4europe good rest. For example, people gameusdcan go out to enjoy themselves or get meinwowgoldtogether with relatives and friends to talk with each storeingameother or watch interesting video tapes with the speebiewhole family.
Everyone spends agamegoldweekends in his ownmmoflyway. Within two days,some people can relax themselves by listening to music, reading novels,or watchingogeworld films. Others perhaps are more active by playing basketball,wimming ormmorpgvipdancing. Different people have different gamesavorrelaxations.
I often spend weekends withoggsalemy family or my friends. Sometimes my parents take me on a visit to their old friends. Sometimesgamersell I go to the library to study or borrow some books tommovirtexgain much knowledge. I also go to see various exhibition to broadenrpg tradermy vision. An excursion to seashore or mountain resorts is my favorite way of spending weekends. Weekends are always enjoyable for me.
不動産お見合い網頁設計ショッピング枠 現金化
辦理婚姻訴訟、外遇徵信、家庭暴力、監護權取得、尋人查址及工商蒐證等服務的新女人徵信社
When the Wow Gold wolf finally found the wow gold cheap hole in the chimney he crawled cheap wow gold down and KERSPLASH right into that kettle of water and that was cheapest wow gold the end of his troubles with the big bad wolf.
game4power.
The next day the Buy Wow Goldlittle pig invited hisbuy gold wow mother over . She said "You see it is just as Cheapest wow goldI told you. The way to get along in the world is to do world of warcraft gold things as well as you can." Fortunately for that little pig, he buy cheap wow gold learned that lesson. And he just wow gold lived happily ever after!.
花蓮旅遊,花蓮租車,花東旅遊,花蓮租車,花蓮租車,花蓮旅遊,租車公司,花蓮旅行社,花蓮旅遊景點,花蓮旅遊行程,花蓮旅遊地圖,花蓮一日遊,花蓮租車,花蓮租車旅遊網,花蓮租車,花蓮租車,花蓮租車,花東旅遊景點,租車,花蓮旅遊,花東旅遊行程,花東旅遊地圖,花蓮租車公司,花蓮租車,花蓮旅遊租車,花蓮租車,花蓮旅遊,花蓮賞鯨,花蓮旅遊,花蓮旅遊,租車,花蓮租車,花蓮租車 ,花蓮 租車,花蓮,花蓮旅遊網,花蓮租車網,花蓮,租車,花東 旅遊,花蓮 租車,花蓮,旅遊,租車公司,花蓮,花蓮旅遊,花東旅遊,花蓮地圖,包車,花蓮,旅遊租車,花蓮 租車,租車,花蓮租車資訊網,花蓮 旅遊,租車,花東,花東地圖,租車公司,租車網,花蓮租車旅遊,租車,花蓮,賞鯨,花蓮旅遊租車,花東旅遊,租車網,花蓮海洋公園,租車 ,花蓮 租車,花蓮,花蓮旅遊,花蓮租車公司,租車花蓮旅遊,花蓮租車,花蓮租車公司,花蓮一日遊,花蓮包車,花蓮租車網,花蓮旅遊,花蓮租車,花蓮旅行社,花東旅遊,花蓮包車,租車,花蓮旅遊,花蓮租車,花蓮一日遊,租車服務,花蓮租車公司,花蓮包車,花蓮旅遊,花蓮租車,花蓮租車公司,花蓮一日遊,花蓮包車,花蓮租車網,花蓮旅遊,花蓮租車,花蓮旅遊,花蓮租車,花蓮租車公司,花蓮一日遊,花蓮租車,租車網,花蓮租車公司,花蓮旅遊,花蓮旅遊,花蓮租車,花蓮租車公司,花蓮租車公司,花蓮一日遊,租車花蓮,租車服務,花蓮旅遊,花蓮租車,花蓮租車公司,花蓮一日遊,花蓮旅遊,花蓮賞鯨,花蓮旅遊,花蓮租車,花蓮租車公司,花蓮一日遊,花蓮包車,花蓮租車網,花蓮旅遊,花蓮租車,花蓮租車公司,花蓮一日遊,租車花蓮,花蓮租車網,花蓮旅遊,花蓮租車,花蓮租車公司,花蓮一日遊,租車花蓮,花蓮租車網,花蓮旅遊,花蓮租車,花蓮租車公司,花蓮一日遊,花蓮包車,花蓮,花蓮旅遊,花蓮租車,花蓮租車公司,花蓮一日遊,花蓮包車,花蓮租車網,花蓮旅遊,花蓮租車,花蓮租車公司,花蓮一日遊,花蓮包車,花蓮租車網,花蓮旅遊,花蓮租車,花蓮租車公司,花蓮一日遊,花蓮包車,花蓮租車網,租車公司,花蓮租車,花蓮租車公司,花蓮一日遊,花蓮旅遊,花蓮旅遊租車,花蓮租車網,花蓮租車,花蓮一日遊,租車花蓮,花蓮租車,花蓮旅遊租車,花蓮租車,花蓮租車旅遊,花蓮租車,花蓮旅遊,花蓮旅遊,花蓮包車,花蓮溯溪,花蓮泛舟,花蓮溯溪旅遊網,花蓮旅遊,花蓮民宿,花蓮入口網,花蓮民宿黃頁,花蓮旅遊,花蓮租車,租車公司,花蓮旅遊租車,花蓮租車,租車,花蓮旅遊,花蓮租車,花東旅遊,花蓮賞鯨,花蓮旅遊,花蓮泛舟,花蓮賞鯨,花蓮溯溪,花蓮泛舟,花蓮泛舟,花蓮溯溪,花蓮旅遊,花蓮旅遊,花蓮租車,花東旅遊,花蓮,花東,花蓮旅遊,花東旅遊,花蓮租車,花蓮,花東,花蓮旅遊,花蓮租車,花東旅遊,花蓮旅遊,花蓮租車,租車,花蓮旅遊,花蓮租車,花蓮旅遊租車,花蓮旅遊,花蓮租車,花蓮,花東旅遊萬事通,花蓮旅遊,租車,花蓮旅遊,花蓮租車,花蓮,花蓮旅遊,花蓮租車,花蓮旅遊,花蓮租車,花蓮租車,花蓮租車,花蓮旅遊,花蓮租車,花蓮旅遊,花蓮租車,花蓮旅遊,花蓮租車,花蓮旅遊,花蓮租車,花蓮租車,花蓮包車,花蓮旅遊,花蓮租車,花蓮租車旅遊網,花蓮太魯閣,花蓮旅遊網,花蓮包車,花東旅遊,花蓮旅遊行程,花蓮旅遊景點,花蓮租車資訊網,花蓮租車網,花蓮租車公司,旅遊租車,花蓮租機車,花蓮包車推薦,花蓮包車,花蓮包車 t4,花蓮黃頁,花東租車,花東包車,花蓮旅行社,花蓮旅遊資訊網,花蓮旅遊景點地圖,花蓮旅遊景點介紹,花蓮旅遊路線圖,花蓮旅遊資訊,花蓮旅遊地圖map,花東旅遊景點map,花東旅遊map,花蓮旅遊blog
花蓮旅遊,花蓮租車,花東旅遊,花蓮租車,花蓮租車,花蓮旅遊,租車公司,花蓮旅行社,花蓮旅遊景點,花蓮旅遊行程,花蓮旅遊地圖,花蓮一日遊,花蓮租車,花蓮租車旅遊網,花蓮租車,花蓮租車,花蓮租車,花東旅遊景點,租車,花蓮旅遊,花東旅遊行程,花東旅遊地圖,花蓮租車公司,花蓮租車,花蓮旅遊租車,花蓮租車,花蓮旅遊,花蓮賞鯨,花蓮旅遊,花蓮旅遊,租車,花蓮租車,花蓮租車 ,花蓮 租車,花蓮,花蓮旅遊網,花蓮租車網,花蓮,租車,花東 旅遊,花蓮 租車,花蓮,旅遊,租車公司,花蓮,花蓮旅遊,花東旅遊,花蓮地圖,包車,花蓮,旅遊租車,花蓮 租車,租車,花蓮租車資訊網,花蓮 旅遊,租車,花東,花東地圖,租車公司,租車網,花蓮租車旅遊,租車,花蓮,賞鯨,花蓮旅遊租車,花東旅遊,租車網,花蓮海洋公園,租車 ,花蓮 租車,花蓮,花蓮旅遊,花蓮租車公司,租車花蓮旅遊,花蓮租車,花蓮租車公司,花蓮一日遊,花蓮包車,花蓮租車網,花蓮旅遊,花蓮租車,花蓮旅行社,花東旅遊,花蓮包車,租車,花蓮旅遊,花蓮租車,花蓮一日遊,租車服務,花蓮租車公司,花蓮包車,花蓮旅遊,花蓮租車,花蓮租車公司,花蓮一日遊,花蓮包車,花蓮租車網,花蓮旅遊,花蓮租車,花蓮旅遊,花蓮租車,花蓮租車公司,花蓮一日遊,花蓮租車,租車網,花蓮租車公司,花蓮旅遊,花蓮旅遊,花蓮租車,花蓮租車公司,花蓮租車公司,花蓮一日遊,租車花蓮,租車服務,花蓮旅遊,花蓮租車,花蓮租車公司,花蓮一日遊,花蓮旅遊,花蓮賞鯨,花蓮旅遊,花蓮租車,花蓮租車公司,花蓮一日遊,花蓮包車,花蓮租車網,花蓮旅遊,花蓮租車,花蓮租車公司,花蓮一日遊,租車花蓮,花蓮租車網,花蓮旅遊,花蓮租車,花蓮租車公司,花蓮一日遊,租車花蓮,花蓮租車網,花蓮旅遊,花蓮租車,花蓮租車公司,花蓮一日遊,花蓮包車,花蓮,花蓮旅遊,花蓮租車,花蓮租車公司,花蓮一日遊,花蓮包車,花蓮租車網,花蓮旅遊,花蓮租車,花蓮租車公司,花蓮一日遊,花蓮包車,花蓮租車網,花蓮旅遊,花蓮租車,花蓮租車公司,花蓮一日遊,花蓮包車,花蓮租車網,租車公司,花蓮租車,花蓮租車公司,花蓮一日遊,花蓮旅遊,花蓮旅遊租車,花蓮租車網,花蓮租車,花蓮一日遊,租車花蓮,花蓮租車,花蓮旅遊租車,花蓮租車,花蓮租車旅遊,花蓮租車,花蓮旅遊,花蓮旅遊,花蓮包車,花蓮溯溪,花蓮泛舟,花蓮溯溪旅遊網,花蓮旅遊,花蓮民宿,花蓮入口網,花蓮民宿黃頁,花蓮旅遊,花蓮租車,租車公司,花蓮旅遊租車,花蓮租車,租車,花蓮旅遊,花蓮租車,花東旅遊,花蓮賞鯨,花蓮旅遊,花蓮泛舟,花蓮賞鯨,花蓮溯溪,花蓮泛舟,花蓮泛舟,花蓮溯溪,花蓮旅遊,花蓮旅遊,花蓮租車,花東旅遊,花蓮,花東,花蓮旅遊,花東旅遊,花蓮租車,花蓮,花東,花蓮旅遊,花蓮租車,花東旅遊,花蓮旅遊,花蓮租車,租車,花蓮旅遊,花蓮租車,花蓮旅遊租車,花蓮旅遊,花蓮租車,花蓮,花東旅遊萬事通,花蓮旅遊,租車,花蓮旅遊,花蓮租車,花蓮,花蓮旅遊,花蓮租車,花蓮旅遊,花蓮租車,花蓮租車,花蓮租車,花蓮旅遊,花蓮租車,花蓮旅遊,花蓮租車,花蓮旅遊,花蓮租車,花蓮旅遊,花蓮租車,花蓮租車,花蓮包車,花蓮旅遊,花蓮租車,花蓮租車旅遊網,花蓮太魯閣,花蓮旅遊網,花蓮包車,花東旅遊,花蓮旅遊行程,花蓮旅遊,花蓮 租車,花蓮租車資訊網,花蓮租車旅遊,花蓮旅遊租車,租車,花蓮旅遊推薦,花蓮旅遊包車,花蓮租車,花蓮,花蓮租車,花蓮地圖,花蓮旅遊優惠,花蓮旅遊資訊網,花蓮旅遊景點,賞鯨,花蓮行程,花蓮旅遊,花蓮旅遊租車,花東旅遊景點,花東旅遊行程,花蓮旅遊blog
Are these Tiffany and Company necklaces realy Tiffany and Company or are they a knock off of the real one?
Tiffany & Co sliver jewelry and diamonds provider.Selections include silver rings, silver necklaces and the other Jewellery
Tiffany and Co. has an unsurpassed reputation for sophisticated luxury. The tiffany jewellery is exquisite.
Tiffany ringsTiffany ringTiffany RingsTiffany BraceletTiffany ringStore your Tiffany sterling silver jewelry in tarnish prevention cloths or bags . The treated cloth slows down the tarnishing process and keeps the tiffany jewelry from rubbing against harder jewelry that can scratch it. Try to to keep your tiffany pendants in a cool, dry place Tiffany necklacestiffany necklaces
Post a Comment