ceronman
2. Even with my Mastercard credit card, the process is still inconvenient. For small purchases, it's fine. But for larger ones, there is an annoying second factor authentication, I have to enter a special password, and the wait to receive an SMS.
3. Visa and Mastercard fees. Most of the time these are paid by the merchant. But sometimes the customer has to pay more if the payment method is credit card. Some places don't accept these at all.
In general iDEAL is simple, secure and convenient. Not only to pay online, but also for example for splitting a bill with friends. I'm very happy to see this being adopted more widely in Europe.
What do you have against this pattern? Or what is a better alternative?
The richest, most powerful organizations are spending billions every month to make it more addictive, to reach more people.
- You can add new traces, or modify/disable existing ones at runtime without having to recompile and rerun your program.
- Once you've fixed the bug, you don't have to cleanup all the prints that you left around the codebase.
I know that there is a good reason for debugging with prints: The debugging experience of many languages suck. In that case I always use prints. But if I'm lucky to use a language with good debugging tooling (e.g Java/Kotlin + IntelliJ IDEA), there is zero chance to ever print for debugging.
struct Constant { value: i32 }
struct BinaryPlus { lhs: i32, rhs: i32 }
trait Evaluate {
fn evaluate(&self) -> i32;
}
impl Evaluate for Constant {
fn evaluate(&self) -> i32 { self.value }
}
impl Evaluate for BinaryPlus {
fn evaluate(&self) -> i32 { self.lhs + self.rhs }
}
// Adding a new operation is easy. Let's add stringify:
trait Stringify {
fn stringify(&self) -> String;
}
impl Stringify for Constant {
fn stringify(&self) -> String { format!("{}", self.value) }
}
impl Stringify for BinaryPlus {
fn stringify(&self) -> String { format!("{} + {}", self.lhs, self.rhs) }
}
// How about adding new types? Suppose we want to add FunctionCall
struct FunctionCall { name: String, arguments: Vec<i32> }
impl Evaluate for FunctionCall {
fn evaluate(&self) -> i32 { todo!() }
}
impl Stringify for FunctionCall {
fn stringify(&self) -> String { todo!() }
}To me it looks like this is exactly the expression problem. The expression problem is not about adding methods to a trait, it's about adding an operation to a set of types. In this case every operation is defined by a single trait.
The idea behind the expression problem is to be able to define either a new operation or a new type in such a way that the code is nicely together. Rust trait system accomplish this beautifully.
> That's not unique to Rust, you can add new interfaces in any language...
Many languages have interfaces, but most of them don't allow you to implement them for an arbitrary type that you have not defined. For example, in Java, if you create an interface called `PrettyPrintable`, but you can't implement it for the `ArrayList` type from the standard library. In Rust you can do this kind of things.
The orphan rule only disallow impls if both the trait and the type are defined outside the crate.
But in this example if you are adding a new type (struct) or a new operation (trait), well this new item should be in your crate, so all the impls that follow are allowed.
If you are interesting in learning in more detail how to write a C compiler, I highly recommend the book "Writing a C Compiler" by Nora Sandler [0]. This is a super detailed, incremental guide on how to write a C compiler. This also uses the traditional architecture of using multiple passes. It uses its own IR called Tacky and it even includes some optimization passes such as constant folding, copy propagation, dead code elimination, register allocation, etc. The book also implements much more features, including arrays, pointers, structs/unions, static variables, floating point, strings, linking to stdlib via System V ABI, and much more.
Tim Cook explains it better that I could ever do:
The product looks polished and I definitely see myself using it. My only concern is: Are they taking VC money? Is this going to be enshittified to death trying to pursue a 1000x investment return?
New Kindle e-readers no longer appear on computers
I only pay this to skip ads, but a lot of content creators still have their own ads on the videos. There doesn't seem to be enough value to justify such price hike. I am likely to cancel my subscription.
I can tell you that this code is very easy to read if you are familiar with Clojure. In fact, this example is lovely! Seeing this code really makes me wanting to try this library! Clojure has this terse, yet readable aesthetic that I like a lot.
But I completely understand you because at some point Clojure code also looked alien to me. You are not broken for having familiarity with some style of code. Familiarity is something you can acquire at any time, and then this code will be easy to read.
True hard-to-read code is one that is hard to understand even if you master the language it is written in.
I also wrote a post about it: https://ceronman.com/2021/07/22/my-experience-crafting-an-in...
I ended up having two implementations: One in purely safe Rust and another one with unsafe.
Note that if you're interesting in the "object manager" approach mentioned, I did that in my safe implementation, you can take a look at https://github.com/ceronman/loxido
I like Rust, but I consider this very, very unlikely.
Rust has actually brought more choice to the programming language scenario. If we're talking about monoculture, let's talk about C/C++. For decades this was the only viable option for systems programming. All new languages were focusing on a higher lever. Languages for lower level stuff were rare. There was D, but it never got enough traction.
Then Rust appeared and there is finally an alternative. And not only that, I because of that, other language designers decided to create new systems languages, and now we have Zig, and Odin, and Vale, etc.
So if anything, Rust is helping in breaking the monoculture, not creating it. C and C++ are not going away, but now we have alternatives.
And I think it's important to acknowledge that even if you don't like a language, if you see a bunch of software being written in such language, it's because the language is useful. I don't like C++ but I admit it's damn useful! People are writing interesting software in Rust because they find it useful.
It's not them, it's us: the real reason teens are 'addicted' to video games
[1] https://en.wikipedia.org/wiki/Microsoft_Dangerous_Creatures
And even with this impressive reduction in resource usage, it's actually huge for 1987! A PC of that age probably had 1 or 2 MB of RAM. The Super NES from 1990 only had 128Kb of RAM. Super Mario Word is only 512KB.
A PlayStation from 1994 had only 2MB of system RAM. And you had games like Metal Gear Solid or Silent Hill.
I assume that for very short-lived programs, a stack based interpreter could be faster. And for long-lived programs, a JIT would be better.
This new IR seems to be targeting a sweet spot of short, but not super short lived programs. Also, it's a great alternative for environments where JIT is not possible.
I'm happy to see all these alternatives in the Wasm world! It's really cool. And thanks for sharing!
My criticism was at the idea of using a RISC-V emulator as a scripting platform. And I'm not saying that it doesn't work, only that I personally think that Web assembly seems a better option for that particular use case.