Luck is harder to quantify, but at the very least competitors like common lisp didn't have much of it.
597 karma · joined February 12, 2019
Luck is harder to quantify, but at the very least competitors like common lisp didn't have much of it.
Since I didn't use dirty processes in elixir it did make me forget about this obvious issue you pointed out, that for a mutable language like Julia can happen in every thread, but that's not something that limits the expressiveness of the model, but something that requires consideration to avoid while programming and language level mechanisms to protect the thread (at the very least the ability to define timeouts that can throw an exception on any spawned process) or maybe a future framework on top of it that handles this in a safer way (something like Akka). I can only hope Julia can achieve the full potential of it's multithreading model.
Having 1 kernel thread for each CPU thread means that your program can use all available CPU threads at the same time (so you get all the parallelism available within the machine), and having a language based scheduler for each thread means you can have minimal overhead (no need to do a system call) to create a new concurrent execution (meaning lightweight/green threading similar to what python allows, except being automatically distributed by the language within all kernel/cpu threads). In Elixir this means you can create millions of processes even though the OS will only see one thread per logical cpu thread, and I never felt the limitation of this abstraction over multiprocessing (of course, Julia is definitely nowhere near as mature - and maybe never will due to stuff like preemptive scheduling and parallel garbage collection that is easier to implement in a language with only immutable types, though it seems to be moving along, and in Julia 1.7 the processes being able to move between kernel threads solving the issue mentioned in that discussion you linked).
A gyroscope is used to detect orientation/angular velocity (spinning), the sensor to add the other degrees of freedom is already there in most modern controllers and smartphones (the accelerometer). The issue is still accuracy I'm afraid.
>Do you need to rotate the yaw of your hand? Nope.
I'd certainly enjoy to open doors and make a simple goodbye gesture in VR.
And finally, you example (splatoon 2) only needs to compute 2 degrees of freedom in movement (rotation left-right - or yawing, rotation down-up - or pitching, since rolling isn't relevant with a dot target), while VR systems depend on 6 degrees of freedom (yawing, pitching, rolling, elevating, strafing and surging - all of these for at least 3 devices at the same time: your head, left hand and right hand). Unfortunately controls in VR are quite complicated, and accelerometers, gyroscopes (and magnetometers which are also used in VR systems to know the reference to the floor) are simply insufficient (but necessary since the positional sensors can't keep track all time with occasional occlusion, such as having one hand passing over the other or leaving the tracking area), which is why the same sensors on the switch are used in every VR headset and controls in addition with even more sensors and algorithms.
EDIT: the camera system also helps a lot with defining gaming boundaries in the room and being able to quickly see if I accidentally leave it, I already punched my monitor once and that's with a barrier that always get visible when I approach something in my room.
[1] https://docs.julialang.org/en/v1/manual/style-guide/#Avoid-t...
Though for intentional uses of unions, most of the time I use a union of a success type or an error type, or a union of a type and null, or a union of type and missing. They could all be special cases, but I don't see the point of not being just one mechanism.
The point is that simple concepts are nice to explain for a beginner, but what actually built your intuition in how to use objects is the years and years learning and experiencing it's benefits and pitfalls. With multiple dispatch it's the same, but since few languages use it (and even fewer, if any, pushes it everywhere like Julia does) most people didn't experience this process.
For me when I'm using a function I just consider them as self-contained abstractions over the arguments. For example there are hundreds of implementations of sum (+), which in practice I ignore and only think about the concept of addition no matter what arguments I give and I trust the compiler/library to find the optimal implementation of the concept or fail (meaning I have to write one myself). If I'm writing a method (or function) I consider arguments as whatever acts the way I need so that I can implement the the concept on them (for example if I'm writing a tensor sum I just consider arguments as n-dimensional iterable arrays and implement assuming that - and declare for the compiler when my method is applicable, without having to care about all other implementations of sum - if anyone needs a scalar sum them that person can implement it and through collaboration we all expand the concept of sum).
And the fact that whoever uses a function can abstract away the implementation, and whoever writes a function can abstract away the whole extension of the arguments (through both duck typing and the fact that the compiler will deal with choosing the correct implementation of the concept) means everything plays along fine without having to deal with details of each side.
I used to listen to songs with a wired conventional headphone for when I wanted to isolate myself from distractions for high attention work, but range limitations like the cable connected to the PC didn't allow me to move freely, no transparency mode so I had to take them out to talk with anyone, no multipoint bluetooth so I had to take them out to answer my phone and not having cables and being light in general just means I even forget I have them on. Now with a sony 1000xm4 basically all those opportunities to have my ears rest became unnecessary.
Add to that the fact that the ANC just opens up the possibility of listening to less fatiguing and attention drawing songs, so while I may listen to lower volumes I might also listen for longer periods and with less interruptions. Not to forget services like spotify with the possibility of listening to an eternally long playlist without any thought (while with a CD or mp3 playlist it would eventually reach an end from which I'd have to stop and think if I want to continue listening).
The intention was to merge the fork into the main language making Swift differentiation tools first class within the language.
In Julia, if the DataFrame library is missing something I can just loop like an array and have a method that works just as well as if the library provided it, the CSV, DB and table processing libraries all use the same conventions so if library "A" solves my issue I'm not forced to use the same library "A" serialization method. Basically instead of twisting the logic to what I'm given, I just fill in the blanks. Sure Julia has way more blanks, but Julia also has half of the age of some of the Python's library I use, it's more about the maturity of the community than anything to do with the design choices of the language and I can only hope it gets better and better with time.
But after listening to the talk, I went from thinking that Elixir was not a good fit to ML to actually excited with the future. Elixir's pipes are definitely a beautiful and concise way to define transformations, and we already have nice examples of them with Streams and Ecto.Multi that even make it surprisingly nice to debug the readable "tape", and being immutable itself allows it to nicely avoid the hardest parts in translating the language into an execution graph both for the creators of the library and for the user. Modifying the if macro to embed the conditional within the "tape" might be a little too much magic though.
The difference would start when you get later a different entity like for example an Organization. Now you have to either create a save_items_org (and check which one it is to choose the correct method) or you add the same check to save_items(Union[Client,Organization]...) and all other methods. If you had used the object then it would be client.save_items() or org.save_item(). Using functools.singledispatch or Julia, save_items(org...) and save_items(client...) will work like the object version and dispatch without trouble and keep as concise as the object version.
Now, the difference with Julia, is that Python's native dispatch capability ends here. If you now want a method to link Users with Users, Users with Organizations and Organizations with Organizations (sorry for the weird usecase, I don't want to add more types) you can just implement in Julia a link(Users, Organization), link (Organization, Organization), link(User, User) and any combination and whatever combination of User and Organization you receive it will dispatch to the correct version (while in Python you'll be forced to do the runtime check with an if to choose the implementation). For example the product operator (*) in Julia has around 300 implementations for all kinds of combinations of arguments, and the compiler makes it extremely fast by inferring and doing static dispatch.
For example, what other dynamic languages do like verbosely typing everything doesn't really work in Julia (the compiler already knows pretty much every type even without hints), what works is treating the variable as a polymorphic container instead of a dynamic container: you don't know yet what type the variable has (only the behaviour), but whatever it is you should avoid changing it if possible (what they call type stability). Which is kinda why it might not be obvious reading proper high performance Julia code, as it is not something you do to make it fast, but what you don't do (change a variable type, forcing the compiler to create a low performance dynamic box, plus other stuff like global variables).
For example it might be possible to AoT compile parts of the code (as long as the types are fully defined) to export as a standalone library, and if that happens it would be beneficial to write the number crunching libraries for glue languages in Julia. I mean, there are already those (like DiffEq to Python and R), but if it's a binary that could have just as easily come from C it would be even better. And there are already works along this path, including for wasm deployment.
The multithreading in Julia is very fast and easy to use, and I'm sure it will become robust and safer as well as the language gets older, which can very well allow for an Akka style framework that allow for large software with both high reliability (thanks to stuff like supervision trees) and structured code (since like Julia's ecosystem design favors small libraries composing with each other, the future of large Julia codebases could become the composition of many small high level but fast actors).
There is also lots of interests in work-arounds on the garbage collector, like improved support to immutable structures (like 1.5 improvements on structs with references to mutable structures). It's possible that you might be able to more reliably write parts of the code that do not allocate (or allocate in predictable ways), so you'll be even handle those realtime code loops.
Sure this is very speculative, but look at Python today compared to when it had Julia's age. It took 8 years since Julia became public to get to this point (2 years since it got the first stable release, 1 year since it got it's multithreading model), it will surely be different when it has triple that age.
[1] https://en.wikipedia.org/wiki/Racket_features#Language_Exten...
It's not a direct comparison of course (nor it is a Lisp), but here is an example of linear optimization in a library that uses macros to make it a DSL closer to the description (in Julia @ before a name means it's macro, so it's easy to see) and one that uses methods:
https://nbviewer.jupyter.org/github/jump-dev/JuMPTutorials.j...
https://www.cvxpy.org/examples/basic/linear_program.html
If in the Julia example they if @variable was a function, then x >= 0 would have been evaluated immediately and it would fail since x was not defined (and if it was x >= 0 would return a boolean). To emulate that you'd probably have to pass a string "x >= 0", which the function would then have to parse (it would be a DSL as well, but one you're writing from scratch), the difference here is that you can just use the language parser directly and compile already with the result.
The difference is how it's arguments are evaluated, for example if I wanted to make a function that implements a for loop of the form (myfor a from 1 to 10 do (print a)), if it's a function then every argument will be evaluated immediately, so it will try to find a variable called a, from, to, do and it will also try to evaluate (print a) immediately before looping. Macros allows for delayed evaluation, as myfor will receive all arguments (at compile-time) as symbols instead of values, which you can then rearrange in a form that can evaluate properly at runtime. You can also go further if you actually want to create syntax and use reader macros, which allows you to write your own parser and therefore escape writing directly on the AST (then you can even write a C syntax within Lisp).
And if your question is: do I actually need them? The answer is obviously no as many languages do not support it (and there are even alternatives for many use cases, like lazy evaluation). The advantage is that your language can have a very simple core and features that were not implemented (say a pattern match structure) can be added entirely within userspace (which is also good for testing new functionality before adding to the core language). Macros are also very efficient since they run at compilation (so if you use the macro a lot of time you only have to evaluate them once, unlike functions that will usually have to run it's logic every time it's called). And all of that means that for DSL, it's not just making a nice adaptation for your domain within the host language, but effectively writing an optimized language for your domain reusing the compiler of the host language without having to change it's source code.
Lisp on the other side not only had less of that collective experience due to becoming less popular, but it was also famous as the language that gives super powers allowing programmers to do 10x more, so the experience was also biased for single dev performance. The Lisp Curse is a cultural problem, not a technological one, you don't need to reinvent stuff just because it is easy (and fun).
I'm optimistic though since the new generation of languages (closure, elixir, julia, nim, rust) is increasingly going against the rooted belief in OOP (stuff like inheritance) and incorporating more Lisp features like macros, code as data and everything as expression. This means more and more large dev groups will have access to the tools and reason to make it scalable in order to get a little of that super power under control.
But seriously, for me is something similar to Python vs Ruby (I used to prefer programming in Ruby before Python became the default ML language and made so I pretty much had to change). Like Ruby, Julia is a language that I can adapt to the problem instead of having to adapt the problem to the language. In Python there is only one obvious way of doing it (at the higher level) no matter what the problem is, usually some hard to read chain of pandas transformation followed by not much better numpy/jax or pytorch method. In Julia I feel less restricted, and if a problem is clean using loops and arrays I do with loops and arrays, if it's clean with vectorization I do that with broadcasting, if someone enabled some macro that looks almost like a description of the problem I can use that as well.
And the result ends up not being what people fear that having many ways to do something means the programmer will abuse it and write unreadable code golf, but having a more natural approach to each problem makes it easier for me to read after it's done, it's not language A twisted in language B (like those pandas operations), but something that is close to a direct representation of language A that I don't need to convert mentally or even with a dictionary.
In the end my code ends up like python but with an extra end, which, while adding a possibly unnecessary line of code it at least makes it trivial to copy and paste something into the repl (or other part of the code) without worrying about indentation.