So here are a few features of the Ripple system that other cryptos can learn from, as viewed by a programmer.
AccountTxnID and Memos
Sometimes you need to send a transaction with some extra data attached. Whether it's an invoice ID, customer number, or some other business-related information, you have some data that needs to go into the blockchain. This will help you keep track of what transaction did what, give some identifiable information as to the origin of the transaction and so on.
Even Bitcoin recognised the need for this feature by introducing OP_RETURN in 2014. Before that, people used to create unspendable transaction outputs that the system would have to keep track of forever.
Ripple already had that at launch in 2012 in the form of AccountTxnID and Memos. The first is a short field, ideal for including transaction IDs and similar short strings. The latter can store a lot more complex data structures - long strings, multiple hex arrays, that sort of things.
LastLedgerSequence
When building a more complex cryptocurrency system, you have to deal with the fuzzyness of transactions before they enter a block. Essentially, when you send a transaction out, you might not know what will happen to it until it either becomes part of a block, or a conflicting transaction becomes part of a block. If a transaction becomes lost in the network, gets stuck in a processing queue, or there is something else wrong with the system, it's essentially stuck in a limbo. It may be confirmed in the next second, it may never be confirmed, or maybe it will take a few hours.
So here's the problem - how do you handle such transactions? You can try resubmitting them if you have the hex representation of them, but that still doesn't guarantee an outcome. You can try double-spending yourself, but then you have two transactions stuck in a limbo. Do you resubmit a different transaction to credit the same person? Then you might accidentally send them the money twice if you're not careful. All of those outcomes are less than ideal.
Here is where LastLedgerSequence comes in. It's a field you can include in a transaction that allows you to specify when a transaction will DEFINITELY fail. You put a ledger number sometime in the future, and if the transaction is not included before that given ledger number, you know for sure it will NEVER be included in a ledger. The transactions are allowed to fail gracefully in a predictable manner.
Data vs Metadata
First generation cryptos are fairly straightforward. A transaction does one thing and one thing only - move money around. If a transaction gets included in a block it means the transfer went through, if it doesn't - it didn't. There are only two outcomes here.
When talking about a more complex system, there will naturally be more possible outcomes. Maybe a transaction got included in a block and it did exactly what it was supposed to. Maybe it got included in a block but failed to achieve anything. Maybe there are different paths it could've taken to get to the outcome, etc.
This is why Ripple transactions have both data and metadata to them. The first shows what a transaction SHOULD do, the second - what it DID do. This allows the transactions to be more complex, while still ensuring that any given transaction call returns all the information relating to a given transaction.
Built-in, dedicated distributed exchange
An efficient Crypto 2.0 system benefits a lot from having a distributed exchange built into it. While some systems like NXT only allow trading a given IOU for its native token, Ripple goes one step further and treats all currencies the same. You can trade any currency for any other, even to the point of undermining the value of XRPs because of it. It is also a very important part of a few other features.
While systems with smart contracts like Ethereum can mimic the functionality of Ripple's built-in exchange, it would be hard to compete with the efficiency of a dedicated exchange logic. As someone who has experience programming a crypto exchange, I can attest that order sorting and matching can be a complex task that would be hard to efficiently execute in a smart contract. Ripple has the strongest distributed exchange that I've seen in any crypto project.
Trades as part of a payment
In a system with multiple currencies, how do you go from having currency A to sending someone currency B? Quite often, you'll have to take that currency to some sort of market, trade it, then use the resulting funds to send the second currency directly. Alternatively, you use some sort of third party to brokerage the deal, take a cut and take its sweet time to get there.
This is not a case with Ripple. A trade can happen as a part of a payment. Sending money from one address to another is just as simple whether you hold the same currency or not. The currencies don't matter, only the value does.
A Ripple payment that can be fulfilled by 4 different currencies
This feature leverages the power of a distributed exchange to its full potential. Everyone has access to the same market and doesn't need to hold more than one currency to transact with anyone on the network.
Atomic, multi-currency transactions
A big issue with transactions that span multiple currencies is the possibility of the transaction failing partially and the funds ending up in some transitory currency. If you're sending USD and expecting them to end up as GBP, you wouldn't want to end up with EUROs. This would be a bad outcome discouraging people from sending more complex transactions.
Ripple solves that issue by forcing every transaction to be atomic. Either the transaction is fully processed, or it completely fails. There is no way to end up somewhere down the middle. Moreover, there is virtually no limit to how complex a transaction can be. You can send out one type of currency, which would take multiple different routes and touching on multiple currencies before ending up at your destination as the intended currency. It is rather remarkable.
The consensus algorithm and predictable block times
Ripple does not rely on a traditional mining algorithm to create its blocks. Instead, Ripple uses a consensus algorithm to issue its ledgers. While the system is more centralised than most cryptos because of that, it solves a lot of other important issues.
First of all, the block times are quite consistent. You know exactly how often they are created and the interval between the blocks is very short and stable. Secondly, the system is more resilient against front running, making the distributed exchange more honest. Lastly, the system in general is less susceptible to market manipulation by the miners - they can't stall certain transactions or oracle data in hopes of manipulating the market and gaming the system.
Conclusions
While the Ripple system has its flaws, it also has a lot of interesting features other cryptos can learn from.