A lot of people seem to like shared card decks but creating your own cards is part of the learning process, you spent time with the material you want to learn, which is the main thing that helps you learning.
shameless self-plug:
On macos and iOS we found Anki a bit out of place so we build a competitor explicitly for language learning (https://wokabulary.com/).
Looks like a cool app, but a monthly subscription for a content free flash card App is asking too much. (Personally I prefer my learning tools to stay around without monthly payments)
Initially, and for many years, we also tried to not have a subscription but steady development needs to paid somehow, same goes for customer support. If Apple would allow for paid upgrades…
Looks like a fun project and Java really could need a bit of minimalism. I'm always intrigued by small frameworks like Minum et al. even if it's just to learn how things are done in an approachable way.
Love to see stuff like this on HN, and I'm a bit surprised about the negativity in the comments.
Haxe is great for when you want to write an entire application in Haxe, then transpile to multiple targets, and then care about the target platform only to the extent that you want your application to just work.
The various haxe game engines are a good example of this kind of use case, where they transpile your haxe code to C++ or JavaScript and then your transpiled code combines with JavaScript code that the game engine provides or with C++ code that the game engine provides and the result is that everything "just works", both natively and in the browser.
I also have high hopes for this approach in relation to GUI programming (HaxeUI, FeathersUI, etc. are very interesting).
But my usecase was different: I wanted to make an API for my business logic that would transpile to Python, JavaScript and Java, and give a developer on each target platform a native look and feel, as if they were interacting with a native Python API or Java API, etc.
Basically, when you do that, you'll discover that Haxe is too much of a leaky abstraction.
For example when your API requires passing an iterator over Strings or returns an iterator over Strings, you'll discover that this doesn't automagically turn into java.util.Iterator<String> when you transpile to Java. Rather Haxe has its own implementation (haxe.Iterator) that transpiles to some weird Java object that a Java developer will have a difficult time interacting with. ...this is true not just for iterators but for a lot of very basic things like collections, exceptions, etc.
Haxe does expose target-specific things on the Haxe-side, so you can write Haxe code that will accept java.util.Iterator or return java.util.Iterator, but, obviously, java.util.Iterator will not be available when you try to transpile to something other than Java. So whenever you want to just use an iterator, your code is going to be full of "if this platform then behave like x, if that platform then behave like y, ..."
Outside of development around the main Haxe-based game engines, you'll also find that the community is just too thin to properly maintain libraries. For example, several libraries that implement very basic things haven't been touched in years and I discovered that the HashMap implementation in the Haxe standard library is just broken and no one seems to care or notice. It just doesn't handle collisions [1]. ...the only way I can explain that to myself is by assuming that there just aren't enough people using HashMaps on Haxe directly, because the game engines or target platforms provide something else that displaces that functionality or that games are just the kinds of applications where the errors that result from hash collisions aren't noticeable. The advice I got from a seasoned Haxe veteran regarding libraries was to not use haxelib and dependencies at all but instead copy & paste the library code I really needed, fighting hard to keep that to a minimum, and maintain it myself.
It's a pity, because the Haxe language is great, and the ideas behind the architecture are great, but the current implementation IMO just hasn't yet made enough progress on the journey it embarked upon for Haxe to be an option yet for major investments in any non-game software development.
The first time I ran into some problems because some component looked stateless but in fact had state and the constant need to jump into components’ code after my team introduced hooks to our react front-end showed me quickly that I want out of the madness. I still can’t understand how hooks where so celebrated by the community. Such a bad idea for code maintainability.
The fact that Google (and others like FB) have not the same incentives as the company buying the ad-space. Even more, I kinda have to trust Google that they show the ads to as many (real) people as they say. Remember Facebook and the video views metrics [0]? Even more so, I have to trust them that they don't manipulate my ranking after not buying ad space anymore to incentivise me to buy ads again.
If a company has enough budget and it's more about making sure that as many people as possible learn about a product or company, Google Ads may be useful. For niche companies without the funding, I'm not so sure...
While interesting, every time I take a look at the Swift forums I fear that Swift becomes even more bloated. The community seems to like adding every language feature and their grandmother. Introducing a different object model means either some breaking changes or temporarily yet another model/feature.
Swift went from a language that a beginner can understand and learn in a reasonable time to something where you feel you periodically need a CS degree to follow code. I'm waiting for online-guides which subset of Swift we should actually use.
Every WWDC I spent the next 2 month just to learn the new language features. Just to forget them until the next project.
> you periodically need a CS degree to follow code.
I have a CS degree, and the issue is not so much being able to follow the code, but wanting to.
Roughly 99% of the issues the Swift designers appear to care incredibly deeply about are things that have never, in my now almost 40 years of programming, popped up on my radar as something I would be even marginally concerned about.
And that's not because I am generally unconcerned, quite the opposite. Heck, I've been working on my own language for over a decade despite not really being all that much into languages, simply because I strongly believe that things need fixing, badly.
I think it's this (type of) disconnect that is at the heart of the trouble with Apple software development these days.
I think that a lot of the work in languages and techniques, stems from a distrust of programmers. Most companies seem to think their programmers suck, and take a highly defensive posture in their tooling and process.
I started seeing this in the 1990s, with Taligent (their style guide was a fun read), but I think it predates that.
The 1990s also were the times of software that crashed ‘all the time” and had security vulnerabilities so large that they nowadays would be called open doors.
One can also see all that work on languages as trying to create a language where programmers get help preventing such issues, so that they can focus their attention on making stuff users want and that also produces code as performant as what expert programmers could write in the languages of old.
That’s not distrust, but realization that being vigilant about buffer overflows and data races is a part of a programmer’s job that (maybe) can be automated.p without sacrificing performance.
The kind of stuff discussed in this article, for example, can help compilers move data around less, without introducing potential concurrency issues.
Now, whether this accomplishes that? I wouldn’t know.
> The 1990s also were the times of software that crashed ‘all the time”
Still a problem. I need to hard-restart my machine multiple times per day, because of two developer tools that spawn orphan processes, all day long. It seemed to suddenly become a problem, when the M1 came out, so I assume that the fault actually lies in Rosetta 2.
I'm not sure that Swift was ever super beginner friendly. I'm thinking of protocols and how they mix with generics and associated types, as well as "class vs struct" ref/value semantics, in particular.
But, anyway, I do agree that Swift is a mess now. Personally, I think the last salvageable version of Swift was 3. That's not to say that everything added since 3 is bad, but rather that they've done much more harm than good to the language since then.
Examples:
* Swift used to not have a Result type. Rather, you were supposed to mark fallible functions with the `throws` keyword, and the compiler would force callers to handle the possible failure. However, that didn't work with so-called "escaping" callback functions that are passed as arguments and then held to be called at a later time, because there may be nobody around to handle the failure when it's called. (This is as opposed to some functions that are marked as `rethrows`, which guarantees that they execute any callbacks immediately, and therefore can be passed `throws` functions/closures. So, then they added the Result type. The reason this sucks is because now there are two ways to define a fallible function: either mark it `throws` or make it return `Result`. What's even more infuriatingly inconsistent is that a function that is marked `throws` does not specify the type of the `Error` that it throws; however, the `Result` type is actually `Result<T, E>` and does specify the `Error` type. So, which is it? Are we supposed to care about the specific error types or not? Of course people will come up with some rule of thumb or convention around when to use which, but I think it's clear from how the language evolved that this was more-or-less a design back-track.
* Swift has an unapologetically imperative syntax. Almost nothing is an expression, and even handling null/nil involves imperative constructs like `switch`, `if let` and `guard let` blocks. That's fine. It's not my favorite syntax style, but whatever. Until Apple decided that super-imperative code isn't that elegant for writing UI logic. So, they tacked on this God-awful "result builder" syntax/API/feature with annotations and arcane syntax/semantics that is completely out of place in the rest of the language. I feel the same way about property wrappers and dynamic member lookup. They are totally out of place with how the core of the language works.
Before Swift 3 the language has the very stupid increment/ decrement operator pairs.
In C these operators, paired with pointer arithmetic, allow you to write either incredibly terse yet correct implementations (e.g. strcpy as one liner) or more often in practice, conceal horrible defects where your code is hard enough to read that nobody spots the mistake. If it is the 1970s where you are, your CPU might have an increment instruction, and your compiler might not be smart enough to spot that x += 1; is also an increment. So when C was invented this isn't crazy at all.
C++ inherited them from C, for whatever that excuse is worth in the 1980s.
But in a modern language you should either abolish them entirely or, if you can't bear to do that, neuter them enough that most of your programmers won't manage to blow their whole foot off when they try to use them. Swift chose to abolish them. Go keeps an increment operator but you can't use it in expression context, so that way it doesn't have pre/post-increment.
So, to me that's pretty obviously an improvement in Swift, even if it's incompatible.
Well, just going to throw my rule of thumb in there.
I tend to use the Result type in asynchronous code and Throws in things that execute tmmediately.
I find Result much cleaner than the old returns of callbacks, which tended to be 2 optionals, the succesful result, or the error, or worrse, both or neither.
I won’t deny it can’t be abused to make things worse, i complained to a supplier on making a throwable combine publisher.
> I tend to use the Result type in asynchronous code and Throws in things that execute tmmediately.
Sure, but then you have to have a crystal ball to know which functions will or won't ever be called asynchronously. It drives me nuts that a function should have to know how, when, or where it's going to be called.
It doesn't help that working with Result is generally pretty cumbersome (flatMap only gets you so far- you'll either end up with deeply nested (flat)Map chains or have a bunch of switch statement noise).
So, for a while I used to just always prefer returning Result for everything, since it was guaranteed to "work" for both async and sync operations. But, now I've gone the opposite direction. I use `throws` for all my named functions because the are so much more ergonomic to "compose" and I just wrap the call in a `Result {}` closure/lambda when I have to pass it as an async callback.
It is weird. I think both actors and the upcoming ownership model (for Swift 6.0) are important. But they are huge to consume with (hard to understand, big foot-print in compiler).
Maybe at some point, we can have Swift 7.0 which demotes classes to a special type of struct (you cannot without ownership model) like Arc in Rust, and that can get rid of some bloats.
I see two issues when the language evolves: 1. the type system still needs some work, parameterized extensions and non-existential / existential type differences are the two major issue I have. 2. get rid of Foundation on non-Apple platforms. The community should really say Swift 7.0 is the "done" version like Go 1.0 (or Julia 1.0), and we will do fixes, small type system QoL improvements and improve standard libraries and have no plan for 8.0 any time soon.
I barely know anyone using the butterfly keyboard in a work environment who doesn’t have problems with it after a few years. Mine is now out of the repair program period and it would cost more to fix it than its worth. It’s basically EOL and I wonder how many MacBooks face the same fate. What a big waste of resources.
At my first job after university my boss told me he only hired me because of https://codingfriends.github.io/Tincta/ and because I told him confidently that I can learn whatever I don’t know yet
shameless self-plug:
On macos and iOS we found Anki a bit out of place so we build a competitor explicitly for language learning (https://wokabulary.com/).