(are (arguments for (using lisp)) (still valid?))



  • @Bulb said in (are (arguments for (using lisp)) (still valid?)):

    @Kamil-Podlesak said in (are (arguments for (using lisp)) (still valid?)):

    I blame Simula and strongly object to the usual "it's a Java fault", when in fact Java just jumped into already established mainstream bandwagon.

    Smalltalk and Simula are the real culprints, but are you sure the banwagon was mainstream when Java jumped into it?

    Yes, absolutely. Simula was, indeed, always mostly obscure thing outside simulation niche (hence the name), but it clearly served as an inspiration to many.
    Notably, Turbo Pascal 5.5 (1989) and of course C with classesC++ (1982!)
    In 1996 (release year of Java 1.0), OOP was absolutely the hot shit.

    The best illustration is the ultimate Java thing, the worst thing about it and endless source of woe: Design Patterns. The GOF Book has been published in 1994! :wtf:



  • @topspin said in (are (arguments for (using lisp)) (still valid?)):

    How does that make sense or is funny?

    Moon language, probably.


  • Considered Harmful

    @HarryTuttle said in (are (arguments for (using lisp)) (still valid?)):

    Someone once told me that Perl's VM is emulating the inner workings of Forth or Fortran. Not sure what to make of it.

    It's a stack machine, that's as far as the commonality with Forth goes.

    Ed:hanzo:


  • Discourse touched me in a no-no place

    @Kamil-Podlesak said in (are (arguments for (using lisp)) (still valid?)):

    The best illustration is the ultimate Java thing, the worst thing about it and endless source of woe: Design Patterns. The GOF Book has been published in 1994! :wtf:

    They were things that were always rather abused, mostly by people not understanding them much. What they should have been: here's a common name for a particular shape of solution in this type of programming language, with common consequences described. What they became for too many: a quest to shove as many buzzwords as possible into the code, whether or not doing so was either correct or made sense, and without regard for the consequences.



  • @dkf said in (are (arguments for (using lisp)) (still valid?)):

    @Kamil-Podlesak said in (are (arguments for (using lisp)) (still valid?)):

    The best illustration is the ultimate Java thing, the worst thing about it and endless source of woe: Design Patterns. The GOF Book has been published in 1994! :wtf:

    They were things that were always rather abused, mostly by people not bothering understanding them muchat all.

    FTFY
    Just to be sure: I mean the whole concept of Design Pattern. The specific ones are kinda meh anyway.

    What they should have been: here's a common name for a particular shape of solution in this type of programming language, with common consequences described. What they became for too many: a quest to shove as many buzzwords as possible into the code, whether or not doing so was either correct or made sense, and without regard for the consequences.

    Yeah, almost everyone missed the "common name" :wtf: and considered it a "metaprogramming", which leads to argument that "LISP and C++ don't need that because they have templates" :wtf:


  • Discourse touched me in a no-no place

    @Kamil-Podlesak said in (are (arguments for (using lisp)) (still valid?)):

    Just to be sure: I mean the whole concept of Design Pattern. The specific ones are kinda meh anyway.

    What they should have been: here's a common name for a particular shape of solution in this type of programming language, with common consequences described. What they became for too many: a quest to shove as many buzzwords as possible into the code, whether or not doing so was either correct or made sense, and without regard for the consequences.

    Yeah, almost everyone missed the "common name" :wtf: and considered it a "metaprogramming", which leads to argument that "LISP and C++ don't need that because they have templates" :wtf:

    My first reaction on encountering design patterns was mainly "hmm, I've been doing that for a while; I didn't know this sort of thing had a proper name". That's why I've always regarded them as nice but not forcing me to use them or something; I'm able to take them for what they really are, scholarship about how programs are formed.

    The one pattern I miss from Java is doing dynamic dispatch by the real types of the arguments (as you can do with CLOS); using reflection to do it is very tricky (unless you're using a sealed type tree) and there isn't anything like the trick you can do in C# to achieve it (which I believe is nasty). You end up having to write a whole load of bloated observer stuff just to work around the lack of a feature. I've written that in the past, but it's ever so nasty.



  • @dkf said in (are (arguments for (using lisp)) (still valid?)):

    The one pattern I miss from Java is doing dynamic dispatch by the real types of the arguments (as you can do with CLOS); using reflection to do it is very tricky (unless you're using a sealed type tree) and there isn't anything like the trick you can do in C# to achieve it (which I believe is nasty).

    May I ask what is that trick?

    You end up having to write a whole load of bloated observer stuff just to work around the lack of a feature. I've written that in the past, but it's ever so nasty.

    Yeah... with a little bit of foresight, this can be part of classes used by parameters, but it is a bloat. And what's worse: it's hard to read/understand and I have very hard time explaining what does it do and even why. Some well-established term for the concept would help a lot (and even better, a good explanation from someone who can actually explain stuff).


  • Discourse touched me in a no-no place

    @Kamil-Podlesak said in (are (arguments for (using lisp)) (still valid?)):

    May I ask what is that trick?

    Something with an operation related to implementing scripting languages in .NET. I remember reading about it in someone's blog, but not the details or where I read them.

    Sorry I can't help more than that; I've never needed to write C# for work purposes. Tricky edge cases are things I'll have to leave to others.


  • Discourse touched me in a no-no place

    @Kamil-Podlesak said in (are (arguments for (using lisp)) (still valid?)):

    @dkf said in (are (arguments for (using lisp)) (still valid?)):

    You end up having to write a whole load of bloated observer stuff just to work around the lack of a feature. I've written that in the past, but it's ever so nasty.

    Yeah... with a little bit of foresight, this can be part of classes used by parameters, but it is a bloat. And what's worse: it's hard to read/understand and I have very hard time explaining what does it do and even why. Some well-established term for the concept would help a lot (and even better, a good explanation from someone who can actually explain stuff).

    The easiest way is a chain of isinstance tests that call an interface with methods for each of the interesting subclasses that you are dispatching on. Defaulted methods in the interface make that a lot less horrible (when you don't care about most of the possible types most of the time) and doing it all in an interface means you keep the crud out of the classes with real logic. (I think this can be improved a bit with pattern matched sealed hierarchies, but that requires a more recent language profile than I've used.)

    But it is ugly. Native multiple dispatch would be nicer, even if it requires making the dispatch slower in this case (no shit, the cost is there anyway, and having to write it out by hand sucks).



  • @dkf said in (are (arguments for (using lisp)) (still valid?)):

    My first reaction on encountering design patterns was mainly "hmm, I've been doing that for a while; I didn't know this sort of thing had a proper name".

    As far as I remember, the GoF book quite clearly says "here's some things we've seen cropping up in the wild many times, so let's give them some names. They seem to work well in this and that case, have the following properties, and this way to implement them seems to generally work well". In other words, it was quite clearly intended to be descriptive rather than prescriptive.

    Of course all the religious zealots then grabbed a hold of that and ran with it, and started praying to the Holy Book and burning the heretics, just like these things usually go.



  • @ixvedeusi said in (are (arguments for (using lisp)) (still valid?)):

    In other words, it was quite clearly intended to be descriptive rather than prescriptive.

    As a young developer years ago (:belt_onion:), I remember that it was quite useful both to see ways to achieve complex results (and/or interactions), but also to understand pieces of code I'd seen but couldn't make sense of it. "Oh, that was an 'observer' so now I understand why it was written that way and what it was trying to achieve!"

    So yeah, an interesting training tool, but definitely not a reference guide to follow everywhere.

    Then again, it seems to me that the software development community is much more into blindly-following and cargo-culting than other communities, so I'm not surprised it was abused that way.



  • @remi said in (are (arguments for (using lisp)) (still valid?)):

    Then again, it seems to me that the software development community is much more into blindly-following and cargo-culting than other communities

    I'm doubtful about that part (but no more surprised about the abuse). Blindly following the "common wisdom" and turning it into dogma is a very common behavior with humans generally and in no way specific to software development. Most people just don't like to think and prefer that others do it for them.


  • Discourse touched me in a no-no place

    @ixvedeusi said in (are (arguments for (using lisp)) (still valid?)):

    Most people just don't like to think and prefer that others do it for them.

    Thinking is hard. Let's go shopping!!! :doing_it_right:


  • ♿ (Parody)

    @ixvedeusi said in (are (arguments for (using lisp)) (still valid?)):

    @remi said in (are (arguments for (using lisp)) (still valid?)):

    Then again, it seems to me that the software development community is much more into blindly-following and cargo-culting than other communities

    I'm doubtful about that part (but no more surprised about the abuse). Blindly following the "common wisdom" and turning it into dogma is a very common behavior with humans generally and in no way specific to software development. Most people just don't like to think and prefer that others do it for them.

    Gell-Mann Amnesia strikes again!



  • @ixvedeusi I don't know. The domain-specific community in which I work (i.e., the people I'm developing software for) do have their share of "common wisdom" but they also have a good dose of questioning everything (sometimes a bit too much...). This is a (minor) ((sub)branch)) of some scientific domain, and scientific research is well-known for (in theory...) asking questions, so that probably taints things. But most people are not doing any kind of research, just applying other people's results (inb4: so do most academic researchers 🔥). And while we do regularly complain that they do so "blindly," their blindness is, uh, much less blind than software developers' blindness.


  • 🚽 Regular

    @Kamil-Podlesak said in (are (arguments for (using lisp)) (still valid?)):

    May I ask what is that trick?

    Maybe calling a method on an expression of type dynamic, which dispatches at runtime according to the same rules as a static dispatch at compile time would use?

    199f52ab-4687-4c87-8c19-b0a7223b474c-image.png

    Inspect(object) compiles to this, for what it's worth.
    
    	if (<> o__5.<> p__0 == null)
    	{
    		<> o__5.<> p__0 = CallSite< Action<CallSite, UserQuery, object> >.Create(
    			Binder.InvokeMember(
    					CSharpBinderFlags.InvokeSimpleName | CSharpBinderFlags.ResultDiscarded,
    					"Inspect",
    					null,
    					typeof(UserQuery),
    					new CSharpArgumentInfo[2]
    					{
    						 CSharpArgumentInfo.Create( CSharpArgumentInfoFlags.UseCompileTimeType, null ),
    						 CSharpArgumentInfo.Create( CSharpArgumentInfoFlags.None, null )
    					}
    				)
    			);
    	}
    	<> o__5.<> p__0.Target(<> o__5.<> p__0, this, o);
    

    PS: call Inspect with something which isn't a string or an int for a nice StackOverflowException.



  • @Zecc from someone who has never done C# (🎉), the bit that looks weird is specifying the dynamic part when calling the function, as opposed to when defining it.

    I know I'm tainted by C++ (:party_parrot:) but it sounds more logical to me to define a (set of) function(s) as being virtual / override (the same goes for templates, though they're not dynamic but they still achieve the same goal of dispatching to different code depending on types), and then it's entirely transparent for the caller which function ends up being executed, rather than the caller having to say "oh, hey, actually this function might exist in different flavours and I'd like you to pick out the right one." That's a burden on the user of the code that seems weird.

    Of course, in your example this burden is hidden behind the generic Inspect(object o) but that looks to me like a bit of boilerplate just designed to hide the inherent ugliness.


  • BINNED

    @Zecc said in (are (arguments for (using lisp)) (still valid?)):

    <> o__5.<>
    

    The face I made reading this code.


  • 🚽 Regular

    @remi said in (are (arguments for (using lisp)) (still valid?)):

    @Zecc from someone who has never done C# (🎉), the bit that looks weird is specifying the dynamic part when calling the function, as opposed to when defining it.

    Just my way of showing it's the type of the expression at the call site that matters. You can declare the o argument as dynamic and then you don't have to cast it at the call site inside the first Inspect. But that confuses matters. The 'magic' is that calling a function on a dynamic will do dynamic dispatch to the right function. Here's a better example:

    51be0e66-60be-46f0-9cd1-2727fdcc19d6-image.png



  • @dkf said in (are (arguments for (using lisp)) (still valid?)):

    like the trick you can do in C# to achieve

    c# has the "dynamic" data type, which I believe is dynamic dispatch without tricks

    I prefer my things statically typed, I'm glad I don't see people using it, I think people that like dynamic are using dynamic languages



  • @remi said in (are (arguments for (using lisp)) (still valid?)):

    I know I'm tainted by C++ () but it sounds more logical to me to define a (set of) function(s) as being virtual / override (the

    and more performing too



  • @Zecc I see, the dynamic is part of the type, not the function. Still, it remains the responsibility of the caller to ensure that a "virtual" function is called with arguments that are dynamic. That still puts the burden on the wrong side, IMO.

    (again, in your example this is hidden behind the first function, but again that's basically boilerplate code that has to be written to hide what looks to me like a wrong design)



  • @sockpuppet7 said in (are (arguments for (using lisp)) (still valid?)):

    @remi said in (are (arguments for (using lisp)) (still valid?)):

    I know I'm tainted by C++ () but it sounds more logical to me to define a (set of) function(s) as being virtual / override (the

    and more performing too

    Yeah but if you want to do multiple dispatch, which is how this subthread started, the C++ way won't work (you can have static dispatch with e.g. overloads or templates, but for dynamic stuff you've got to hack something, either with some hand-rolled vtable or by listing the cases, to work around this feature simply not existing in the language).

    If you want to do something more complicated it costs more, I'm fine with that. I'm not quite sure how much I would actually need to do it (as opposed to a more clunky solution to achieve the same result in a language without that feature built-in, e.g. C++). But that is an entirely different matter (design vs. usage).



  • @topspin said in (are (arguments for (using lisp)) (still valid?)):

    @Zecc said in (are (arguments for (using lisp)) (still valid?)):

    <> o__5.<>
    

    The face I made reading this code.

    The compiler team calls that an "unspeakable name," an internal symbol generated by the compiler that is guaranteed not to clash with anything in your code, because if you typed it in as normal source code, it would be syntactically invalid.



  • @remi a pointer typed at a base class would do something like this. or do you mean without access to the classes to make they implement your base class / interface? then you're back to the ugly reflection stuff



  • @sockpuppet7 I'm not sure I get what you're saying. But I suspect you're a bit too hung up on the specific example given above, which can be fully and more simply be expressed by virtual functions (and classes) in C++.

    But the subthread was about the more complex idea of dynamically dispatching a call to various functions, based on the types of several arguments (e.g. Inspect(int, int) is not the same as Inspect(int, string) is not the same as Inspect(string, int) etc. but all of those can be called by simply calling Inspect(var1, var2)). I found this wiki page yesterday that explains it pretty well.

    You can't do that natively in C++. You can emulate it with various workarounds (some of them are described in the Wiki page). But they're not direct features of the language, like it apparently is in C#. Those workarounds are going to be either more (boilerplate or weird) code, or worse performances. Likely both at the same time.

    But, back to the C# thing, the part that bothers me is that it is up to the caller to ensure they say "hey, this variable is dynamic, don't forget to dispatch based on it" which sounds wrong to me. The workaround (shown in this subthread and in the Wiki page) is to use another wrapper function around it, but that's ugly boilerplate, which makes the feature less attractive.


  • Discourse touched me in a no-no place

    @Mason_Wheeler said in (are (arguments for (using lisp)) (still valid?)):

    @topspin said in (are (arguments for (using lisp)) (still valid?)):

    @Zecc said in (are (arguments for (using lisp)) (still valid?)):

    <> o__5.<>
    

    The face I made reading this code.

    The compiler team calls that an "unspeakable name," an internal symbol generated by the compiler that is guaranteed not to clash with anything in your code, because if you typed it in as normal source code, it would be syntactically invalid.

    It's unspeakable for other reasons too... 😜

    I mostly prefer to use names with spaces in in such cases; users don't think to write such things. A leading control character is also highly unexpected... and not supported by many programming languages either. Mind you, the simplest unspeakable name is simply an integer string; those don't get parsed as symbols by source languages, but rather as a different syntax class...


  • BINNED

    @dkf an even simpler name is one that isn’t syntactically “unspeakable”, but one that’s syntactically valid but unique. The compiler knows what locals you have and can easily create a name that doesn’t clash with anything. That would have the advantage that you can compile it again. (I assume this was generated from something like a decompiler?)



  • @remi said in (are (arguments for (using lisp)) (still valid?)):

    You can't do that natively in C++. You can emulate it with various workarounds (some of them are described in the Wiki page). But they're not direct features of the language, like it apparently is in C#. Those workarounds are going to be either more (boilerplate or weird) code, or worse performances. Likely both at the same time.

    You actually can do it in C++, because it does have function overloading, although only at compile time. The same is true in C#, except that the "compiler part" is available at runtime (intended for scripting languages, which is why the usage is so awkward in C#).

    Basically, Stroustrup decided that overriding is something completely different and unrelated to overloading and must never be confused (which is why they have similar names, because the C++ design philosophy is :trollface: ). Otherwise, he would have to implement CLOS multiple dispatch.

    But, back to the C# thing, the part that bothers me is that it is up to the caller to ensure they say "hey, this variable is dynamic, don't forget to dispatch based on it" which sounds wrong to me. The workaround (shown in this subthread and in the Wiki page) is to use another wrapper function around it, but that's ugly boilerplate, which makes the feature less attractive.

    As said above - this dynamic part should not be in the language at all, as it is basically just .NET implementation internal thing. IMHO it is exposed only to make C# the "ultimate" .NET language that is superset of every other .NET langauge.



  • @Kamil-Podlesak said in (are (arguments for (using lisp)) (still valid?)):

    You actually can do it in C++, because it does have function overloading, although only at compile time.

    Ergo, you can't do it. Read above (have we reached Remi's point, by which new posts can be answered by pointing to previous ones?), it's all about doing this multiple dispatch at runtime.

    If you want to do it at compile time, C++ also has templates that perfectly fit the bill, except again it's at compile time.

    As said above - this dynamic part should not be in the language at all, as it is basically just .NET implementation internal thing. IMHO it is exposed only to make C# the "ultimate" .NET language that is superset of every other .NET langauge.

    I guess that's a reasonable (?) explanation. At least to me, it very much looks like a hack more than a feature (due to this burden-on-the-caller thing).


  • 🚽 Regular

    I checked out of this conversation a while ago, but since it still seems to be going, I'll just drop this link I've bumped into without further context:


Log in to reply