freenode/#lisp - IRC Chatlog
Search
21:27:57
seok
Would it be a bad design to define a lot of similar classes, say 4000 of them? how big of an overhead would that be?
21:31:22
Xach
seok: not inherently bad, but that number would require some pretty decent justification and abstraction.
21:33:19
seok
But would it be a bad idea to make a prototype for each of those units with (defclass name (unit)) ?
21:34:53
seok
In the former case the blueprints for each of those unit would have to be stored somewhere anyway, so how bad is it to store them as class definitions?
21:39:31
tychoish
I tend to think of classes as "kind of thing" and then have instances for "the collection of things," and have all of the different kinds of things be parameters/slots on the class
21:41:25
tychoish
I heard a trick, I think from like Ward Cunningham or something, where you give yourself three index cards and attempt to model the objects in whatever problem you're working out in terms of the three cards, and it's a bit extreme, but broadly, it's how I model things, I think
21:43:03
mfiano
Inheritance trees quickly turn into graphs in any sophisticated game design, not to mention it is not great for the CPU cache, and after all game development is all about efficient data transmission.
21:44:40
seok
So you'd mach rather a method which makes instances of one definition of class rather than few thousand of them?
21:44:55
mfiano
With inheritance, you keep pushing slots up to the root until you have a "god object" that everything inherits from.
21:45:40
tychoish
seok: it really depends on the use case. I tend to be "small numbers of classes" and "composition over inheritance" but also i don't write games
21:45:57
aeth
Unless they're multiplayer and the code is shared with server code, the processes tend to be short-lived
21:46:48
mfiano
We already have that, to some degree. Virality Engine has been in active development for 4 years and behaves very similarly to Unity or Unreal already, sans the GUI.
21:47:05
aeth
GUI-oriented game engines don't really fit the same niche that Common Lispers are in, so it's doubtful that a CL game engine's editor would use similar principles
21:50:18
aeth
Other engines include https://github.com/borodust/cl-bodge https://github.com/vydd/sketch/ https://github.com/cbaggers/cepl https://gitlab.com/dto/xelf https://github.com/Shirakumo/trial https://gitlab.com/zombie-raptor/zombie-raptor
21:50:40
aeth
There's a fairly active community over at #lispgames but it hasn't really been active this month. The summer? Corona? Who knows
21:50:56
aeth
A few other engines haven't been active in a while, e.g. https://github.com/BradWBeer/CLinch
21:51:21
mfiano
drawing pictures is done by constructing geometry, filling buffers, applying some linear algebra, and writing shaders. Same as any other modern game engine :)
21:52:15
aeth
I think a lot of people were on IRC in the background while at work, and that's suffered a bit in 2020
21:53:28
mfiano
Virality Engine is in the process of a huge overhaul. We had to develop a custom CPU emulator to support the component ordering in an atomic fashion. We're almost done writing that CPU, after nearly a year and a half. That is the reason for the lack of commits, but we are working on it live on stream every week.
21:53:39
aeth
https://github.com/bufferswap/ViralityEngine https://github.com/borodust/cl-bodge https://github.com/borodust/trivial-gamekit https://github.com/vydd/sketch/ https://github.com/cbaggers/cepl https://gitlab.com/dto/xelf https://github.com/Shirakumo/trial https://gitlab.com/zombie-raptor/zombie-raptor https://github.com/BradWBeer/CLinch
21:54:26
aeth
There are lists e.g. on the Lisp games wiki, but they're out of date and incomplete, e.g. still calling Virality "First Light". https://github.com/lispgames/lispgames.github.io/wiki/Common-Lisp
21:56:35
aeth
My engine is Zombie Raptor (2013), which might be the second oldest after dto's xelf (2007???), but progress is glacial because it focuses on high-performance, which has involved... quite a lot of from-scratch work, e.g. my own utility library.
21:57:28
aeth
Quite a lot has spun out of that project over the years, including an entire R7RS-small implementation in Common Lisp that's almost ready. I'm trying to complete it before the end of 2020, which is why I've been neglecting my engine this year.
21:57:39
seok38
So it looks like there are a lot of small groups each working on different game engines
21:57:45
mfiano
Virality Engine is the concatenation and reorganization of code back to 2008 from 3 developers.
21:58:06
seok38
Do each of these game engines serve a different niche? Or is there a chance for one big general game engine?
21:59:09
aeth
CEPL is more of a thing focused on live-coding than a proper engine, Virality is focused on proper architecture, cl-bodge is more about wrapping foreign libraries than most Lispers are comfortable with, and Zombie Raptor is designed around unnecessarily-high performance requirements just to prove that it's possible
21:59:39
mfiano
sketch doesn't have any concepts found in a game engine. bodge is a collection of bindings so more of a framework, etc.
22:00:07
aeth
You could argue that every Common Lisp game engine is actually a game framework since these days, "game engine" often implies that there's an editor
22:00:20
mfiano
A game engine contains collision detection, draw order, prefabs, and other concepts needed for game development.
22:00:59
mfiano
That said, a game engine is nothing more than a set of choices someone made for you, so it is possible a game engine unless very general purpose and developed by hundreds of people, is not the right choice for your game
22:03:51
mfiano
Virality Engine's running game is its editor for the most part. It's just that, everything (about a couple dozen DSLs) is live recompilable, so instead of using that mouse thing, you just redefine a prefab and anything composed from it is updated on the spot, or a texture definition, or a component, or game logic, etc
22:04:48
seok38
mfiano, I've got some game engine specific questions, mind if we move to #lispgames?
22:05:22
mfiano
It also has a custom shader language so GPU functions and their dependencies are also update-able online.
22:06:30
mfiano
I mostly only pay attention to #bufferswap, as its where all my energy is emitted :)
22:07:05
aeth
And as for "why doesn't everyone just work on one engine", this highlights why people have different design priorities. For instance, my engine's basic design philosophy is, essentially, "Do everything at compile time if possible."
22:07:18
aeth
I'll insert some live coding features where possible at some later date, but I mostly focus on elaborate macros.
3:37:11
borei
question - should i expect that function performance generated by macro will be the same like performance of the function created in normal way ?
3:37:57
fwoaroof[m]
There's no difference between typing out the result of macroexpansion and using a macro
3:41:14
borei
my first suspect is that macro generated function is accessing to variable defined in the "let"
4:15:10
aeth
when a DEFUN is under a LET instead of a PROGN (or nothing), then it no longer counts as top-level, so it can actually be slower
4:16:12
aeth
There are a handful of other top-level forms, most notably eval-when: http://www.lispworks.com/documentation/HyperSpec/Body/03_bca.htm
4:16:53
fwoaroof[m]
(I know non-local variable access can have a significant performance impact in python)
4:17:59
beach
Accessing closed-over variables can be slower. It depends on the compiler and how those variables are used.
4:18:46
fwoaroof[m]
I suspected that: in python, it's something like local variables are looked up by indexing into an array, global variables are looked up in a hash-map
4:19:51
aeth
Well, it's more complicated in CL because only dynamic/special variables or constants are portably global, although other globals might exist.
4:23:13
beach
For special variables, you can have deep binding or shallow binding. With shallow binding, and if your implementation uses threads, each variable has a current-value slot, probably in the reified thread object. With deep binding, you have to search the dynamic environment for the latest binding.
4:24:21
beach
The global value of a special variable (which is shared among all threads) a typical implementation has a slot in the symbol for it.
4:27:21
beach
A closed-over variable becomes part of the static environment of the function. And the static environment is passed as an implicit argument to the function. In the worst case, the value would then be kept inside a "cell" in the static environment. So you have two memory accesses to reach it, whereas an argument may be passed in a register.
4:27:49
beach
But if the closed-over variable is not assigned to after creation, the cell can be avoided.
4:28:29
beach
And the compiler can pass the static environment in different ways to avoid some overhead.
4:35:30
beach
So even though x is read-only, it is not the same each time in the anonymous function.
4:36:27
beach
Once it has been accessed there, it can be put in a register of course, if that is what you mean.
4:37:18
fwoaroof[m]
I don't think I was thinking clearly enough: I was thinking that, in some cases you could transform the inner lambda to something like (lambda (y) (+ 1 y))
4:37:59
beach
That would be possible only if you have something like (let ((x 1)) (lambda (y) (+ x y)))
4:41:40
borei
don't know, looks like im missing something very fundamental, and without it i can build full picture
4:42:37
borei
im looking at the macroexpand now - main and biggest difference is how function is accessing "nodes" array
4:43:56
borei
in second case - it's not parameter, and it's not local for the function var, so it need to looked up at higher level. higher level is "let"
4:46:04
borei
is there an option to make that nodes variable "like local" for the function defined in macro ?
4:47:13
borei
hmm, but that is not option in terms of performance because i need to call "let" every time
4:54:50
fwoaroof[m]
Whether or not the binding is a lexical binding depends on whether the variable has been declared special
4:56:40
borei
so with every call it will be creating lexical scope, then destroy it. i did try it yesterday. maybe was using it wrong, but result was even wors
5:01:00
fwoaroof[m]
Cool, I guess you have to decide whether the performance is worth the cost of passing an extra argument around
5:01:40
fwoaroof[m]
I'm not an expert at optimizing CL, though: there maybe some way of putting a LET inside the DEFUN and then declaring nodes DYNAMIC-EXTENT to get some more speed
5:04:01
borei
actually discussion was pretty useful for me, now i understand why im getting a bit better performance introducing one more function - it allows to reduce number of lookups to static environment.
5:04:19
beach
If some object is not passed as an argument, it has to be stored somewhere in the function object, or in a place that is accessible to the code of the function. That access requires a memory access. I don't see how you can get around this.
5:05:46
beach
I guess I should act upon the suggestion of doing a series of presentations for the online Lisp meeting, with the subject how a Common Lisp compiler works.
5:43:28
beach
In my opinion, programmers need to know about compiler design. Not so much in order to create fast code, but in order to avoid guessing what the compiler will do, and in the process, making their code less maintainable. But there are cases, like this one, where such knowledge is needed for creating fast code.
5:53:16
fwoaroof[m]
Yeah, I've been slowly discovering in my professional career why the old lisp books cover the topics they do
5:53:38
fwoaroof[m]
Things like continuations and language design are surprisingly relevant to day-to-day programming
5:57:42
seok38
fwoaroof[m] yeah, for books on other specific languages I wouldn't trust stuff that is printed before 2012