Path: csiph.com!usenet.pasdenom.info!dedibox.gegeweb.org!gegeweb.eu!nntpfeed.proxad.net!proxad.net!feeder2-2.proxad.net!newsfeed.arcor.de!newsspool3.arcor-online.net!news.arcor.de.POSTED!not-for-mail Content-Type: text/plain; charset="UTF-8" Message-ID: <5021733.WrF0io4ur8@PointedEars.de> From: Thomas 'PointedEars' Lahn Reply-To: Thomas 'PointedEars' Lahn Organization: PointedEars Software (PES) Date: Tue, 12 Nov 2013 12:45:54 +0100 User-Agent: KNode/4.10.5 Content-Transfer-Encoding: 8Bit X-Face: %i>XG-yXR'\"2P/C_aO%~;2o~?g0pPKmbOw^=NT`tprDEf++D.m7"}HW6.#=U:?2GGctkL,f89@H46O$ASoW&?s}.k+&. <17113478.8IimEn4RK4@PointedEars.de> Followup-To: comp.lang.javascript MIME-Version: 1.0 Lines: 303 NNTP-Posting-Date: 12 Nov 2013 12:46:13 CET NNTP-Posting-Host: 4a35f4c2.newsspool4.arcor-online.net X-Trace: DXC=VNTBM@kU88Nk:C4l9A;OcO4IUK@[hLNg?mIFY9^hGi5l@N X-Complaints-To: usenet-abuse@arcor.de Xref: csiph.com comp.lang.javascript:21983 chrisrussell41@gmail.com wrote: ^^^^^^^^^^^^^^^^^^^^^^^^ This is Usenet. Your real name should go there. [Added attribution line; please do not remove next time] > Thomas 'PointedEars' Lahn wrote: >> http://pointedears.de/scripts/test/es-matrix/ > > Interesting matrix you've created. I'll need to parse further in order to > identify just specifically which column my work falls in. All of them, I presume. CoffeeScript generates ECMAScript-based code (and each column of the feature table deals with one ECMAScript implementation, all of which should be capable in their current version to parse the code), but not necessarily good one. In fact, the code you have generated suggests what I had suspected for a long time: that the code generated by it is very bad. See below. >>> The core ONMjs classes are dependency-free JavaScript >> There are no classes in production-quality JavaScript yet > > I made no such assertion. Yes you did. I have restored the quote above. By “production-quality JavaScript” I mean a *JavaScript[tm]* script *engine* that is ready for use in production. There has been an implementation of ECMAScript Edition 4, which introduced classes, JavaScript 2.0 (“Epimetheus”), before it was abandoned, but it never was ready for use in production. All other ECMAScript implementations are not (called (only)) JavaScript. There is Microsoft JScript .NET for ASP .NET on IIS that does have classes, and there is ActionScript 2+ for Macromedia/Adobe Flash that does. > Be kind to a C++ programmer who is making an effort to improve their > knowledge and broaden their horizons. I know it's not perfect and can be > improved. Specific criticisms would be helpful. JavaScript[tm] is but one of many implementations of ECMAScript. Client- side ECMAScript implementations, with the exception of ActionScript 2+, are object-oriented languages that use *prototype*-based, not class-based, inheritance: Objects inherit properties from other objects, through a mechanism called “prototype chain”. Nevertheless, objects created using a constructor, or a constructor whose prototype object (the object that its “prototype” property refers to) is in the prototype chain of the prototype object of another constructor, are called “instances” of that constructor in the Specification (hence the “instanceof” operator borrowed from Java). Constructors are (WLOG) functions, and functions are first-class objects, (WLOG) Function instances. >> you are using jQuery > > ... as a convenience in JSFIDDLE examples, yes. Not as a dependency of the > core classes that do not leverage JQuery (or any other library). OK. I found the following in your repository description confusing: | Observer dependencies: JQuery, D3js, Knockout.js >> Contrary to your statement, using the observer pattern, which I would >> consider core functionality as described above > > I don't follow. The ONMjs.Store class provides register/unregisterObserver > methods and a documented API for the callbacks. Would you explain your > point further please. You have snipped my answer so that the quote does not contain my point. But assuming that your previous statement is true, it is moot now. >> I could not find any *relevant* *ECMAScript-based* code written by *you* >> that would be on-topic here. > > http://onmjs.encapsule.org/stage/js/core/ Thanks. > Notwithstanding your objection to authoring in CoffeeScript, the contents > of that directory is original. I'm not saying it's perfect, but it works ^^^^^^^^ > pretty well. ^^^^^^^^^^^^ Sigh. [psf 10.1] > Enough so that I would write and ask you folks for some feedback. It is worse than I initially expected. Let us just look at the generated ONMjs-core-model.js (which already is 21K uncompressed): - You do *a lot* of pointless operations (that also add to the footprint). While | var ONMjs, namespaceEncapsule; | | namespaceEncapsule = (typeof Encapsule !== "undefined" && Encapsule | !== null) && Encapsule || (this.Encapsule = {}); is somewhat forgivable – var namespaceEncapsule = (typeof Encapsule !== "undefined" && Encapsule !== null) ? Encapsule : (this.Encapsule = {}); would have been clearer, although “this.Encapsule = {}” is unnecessary if you return the reference to the object – | Encapsule.code.lib = (Encapsule.code.lib != null) && Encapsule.code.lib | || (this.Encapsule.code.lib = {}); is not. if (!Encapsule.code.lib) { Encapsule.code.lib = (this.Encapsule.code.lib = {}); } is equivalent, more efficient, clearer code. (But the double assignment is still bogus.) - You have functions with more than 5 formal parameters: | buildOMDescriptorFromLayout = function(ONMD_, path_, parentDescriptor_, | componentDescriptor_, parentPathIdVector_, | parentPathExtensionPointIdVector_) { | … | } No function should have more than 5 formal parameters because few people will remember them. Use one Object-typed parameter if you cannot refactor top-down. - You do type-converting comparisons against “null” for no obvious reason: | if (!((ONMD_ != null) && ONMD_)) { if (!ONMD_) { … } is equivalent, more efficient, and clearer. There are no “null pointer accesses” that would need to be avoided in these languages: “null” is the sole value of the Null type, and type conversion (here: to Boolean) is implicit (unless prevented by strict comparison): | >>> var a = [[], [1], false, true, new Date(), function () {}, Math, -1, | 0, 1, NaN, -Infinity, Infinity, null, {}, {x: 42}, /(?:)/, /x/, "", "x", | void 0]; | for (var i = a.length; i--;) | { | var e = a[i]; | console.log(!((e != null && e)), !e); | } | | true true | false false | true true | (4) false false | true true | (2) false false | true true | false false | true true | (5) false false | true true | (2) false false | ← undefined The only thing you do need to avoid to access *standalone identifiers* directly that may not have been declared (which is why the “typeof” operation has been used above). - You throw unformatted strings for exceptions: | throw "Missing object model layout object input parameter! If you | specified the namespace declaration via object reference, check the | validity of the reference."; In order to determine *which* exception was thrown, the caller would have to do something error-prone like try { yourFunction(); } catch (e) { if (e.message == "Missing object model layout object input …") { // … } } when, if you had written, for example, throw new ONMjs.InvalidArgumentError("…"); they could have written try { yourFunction(); } catch (e) { if (e && e.constructor == ONMjs.InvalidArgumentError) { // console.log(e.message); } else { throw e; } } or try { yourFunction(); } catch (e) { if (e instanceof ONMjs.InvalidArgumentError) { // console.log(e.message); } else { throw e; } } or in JavaScript 1.5+ even try { yourFunction(); } catch (e if e instanceof ONMjs.InvalidArgumentError) { // console.log(e.message); } - All your methods are instance methods even when they could have been inherited from a prototype object which would have saved precious heap per instance: | this.getNamespaceDescriptorFromPath = function(path_) { | try { | return | _this.getNamespaceDescriptorFromPathId(_this.getPathIdFromPath(path_)); | } catch (exception) { | throw "ONMjs.implementation.ModelDetails.getNamespaceDescriptorFromPath failure: " + exception; | } | }; “_this” is merely your alias for “this” in the same execution context – | var buildOMDescriptorFromLayout, | _this = this; | – so what's the point? - None of this code is inline-commented and lines are far too long. It *is* hard to debug. And so on. I do not care if this nonsense was generated by CoffeeScript or if it was so in your original design. All I do care about is that the outcome is bad code. What we see here is the result of the common fallacy of overgeneralization, the attempt at a one-size-fits-all solution that is supposed to make things easier (but in the end doesn't). The record shows that it is often better to write code specific to a small purpose, and then combine specific code for a larger purpose – transferring the “one tool for one purpose” approach to general programming if you will. See also: > [Top post] Please don't. -- PointedEars Twitter: @PointedEars2 Please do not Cc: me. / Bitte keine Kopien per E-Mail.