3 ms·
Ok, you can use libraries, of course - so shouldn't say that there is no reuse. But libraries are not the same as built-in syntax. Built-in syntax for the basic
by jstimpfle 4y ago
Ok, you can use libraries, of course - so shouldn't say that there is no reuse. But libraries are not the same as built-in syntax. Built-in syntax for the basic things, as in the Algol-family is a) standard so everybody uses it. b) optimized for the right mix of efficiency as well as redundancy (error detection, skimmability by humans). Talk about "oatmeal with fingerclippings mixed in" - more parens don't add useful redundancy, but keywords and delimiter tokens do.
Too much power for its own good is one thing, but being just not optimized for the common thing is another. How would the following function, randomly picked from what I have open on github right now, look in "Common" Lisp? And if I ask 3 persons to do it, what is the likelyhood that they would pick more-or-less the same approach?
Edit_Array buffer_batch_array_from_linked_list(Arena *arena, Batch_Edit *batch, i32 count){
Edit_Array result = {};
result.count = count;
result.vals = push_array(arena, Edit, count);
i32 counter = 0;
for (Batch_Edit *node = batch;
counter < count && node != 0;
node = node->next){
result.vals[counter] = node->edit;
counter += 1;
}
return(result);
}
- lispm 4y agoCL has built in syntax for function definitions, local variable definitions, type declarations, function calls, loops, assignments, increments, value returning and a lot more. It just uses names operators in prefix position. foo += 1 then is (incf foo). for (...) { ... } is then (loop for ... do ...). ...i32 counter = 0;... is then (let ((counter 0)) (declare (type i32 counter)) ...) and so on...
- reikonomusha 4y agoAs the sibling commenter said, that code admits a relatively standard translation. Without understanding the nuance of your code, and assuming you've made your own data structures and didn't use Lisp's standard ones (e.g., Lisp's native lists for the `batch` object), the translation would be this: (defun buffer-batch-array-from-linked-list (arena batch count) (let ((result (make-edit-array :count count :vals (push-array arena edit count)))) (loop :for counter :below count :for node := batch :then (next node) :for vals := (vals result) :until (null node) :do (setf (aref vals counter) (edit node))) result)) This is very typical Lisp code. Could you adorn this code with type declarations? Yes, and you'd get speed and/or safety benefits by doing so. Depends how much this function "matters" in the larger context.
- klipt 4y agoOne difference that stands out here is that in the original code, the methods "node->next" and "node->edit" both belong to a "node" namespace, so you could have other objects with the same method name, e.g. perhaps "document->edit(patch)", and there would be no collision since they're in different namespaces. But in your lisp version "next" and "edit" appear to be global methods. That seems like it could lead to a lot of naming collisions. Could you still have a document type that you can call "(edit document patch)" on? A preliminary Google search suggests that CLOS methods can't have definitions with a different number of parameters, so now you're stuck with a global "edit" method that can only ever take one parameter.
- reikonomusha 4y agoCommon Lisp has generic functions, as you saw. Readers, writers, and/or accessors to classes are generic. So no issue with naming collisions. (defclass a () ((value :reader value) (next :reader next))) (defclass b () ((value :reader value) (next :reader next))) This is totally valid; I can call VALUE and NEXT on instances of both A and B just fine. But, if generic functions aren't your thing, you can skip calling the functions even and just do (slot-value x 'next) if you really want. This is basically x->next Again, works for any object with a field named by the symbol "next". But it's idiomatic to just call the reader function you defined, since getters can be instrumented, debugged, traced, etc. Some people prefer to call the reader A-NEXT or B-NEXT, but it's not necessary. Regardless of all of that, symbols themselves belong to a namespace, called the "package". So your "edit" and my "edit" methods can have a different number of arguments without issue. (If they do have different arguments, they must mean different things.)
- kazinator 4y agoIn Lisp this is solved with some combination of better names and symbol packages. E.g. you might have some doc-model:edit symbol and file-utils:edit or whatever. The symbols have the same name, but are different objects in different packages. The generic function doc-model:edit is therefore unrelated to file:edit. Packaging at the symbol level means that the package system is relevant to anything whatsoever that is named by a symbol. If you have some logic programming system where you declare some named rules or facts, they can easily go into a package. Symbols which are quoted individually or in a larger literal are in the package system all the same; it's an independent layer.
- creepycrawler 4y agoTo me this code just looks like a lot of boilerplate to just say: (replace (make-array count) batch)
- kazinator 4y agoFirstly, that needs a rewrite in some non-sucky curly brace with pointers: Edit_Array buffer_batch_array_from_linked_list(Arena *arena, Batch_Edit *batch, i32 count) { Edit_Array result(arena, count); // Edit_Array has this thingy called a constructor foreach (node in batch) // Batch_Edit * is somewhere/somehow declared iterable { if (result.full()) // Edit_Array has internal fill index, checked against count break; result.add(batch->edit); // Edit_Array has method to add and increment fill index. } return result; // not a function, drop the parens } The Edit_Array class in the original is of no help whatsoever. Like this coder or language aren't even up to abstract data types with Modula-2.