was it necessary to have another language for these operations? isn't it possible to write the whole runtime in one language?
To be clear: the goal of the scripting language isn't for defining the runtime logic of blockchain validation. No part of Bitcoin Core itself is written in the Bitcoin Script language, just in C++. The goal of the Bitcoin Script language is for customizing the conditions under which transaction outputs can be spent. These scripts are intended to be written by "users" of the system, not by (authors of) the system itself. Of course, in practice they are written and designed by the authors of the wallet software these users use, but it permits a flexibility that wouldn't otherwise exist: wallet authors can develop and experiment with new scripts permitted by the language, without needing to wait for the entire Bitcoin ecosystem to adopt changes to specifically enable their use case.
Would it be possible to not have such a language: certainly. There are several cryptocurrencies that don't have such a concept at all. But this alternative doesn't need to mean that the Script language is replaced by C++ (or whatever other language the validation logic is written in) - it can simply mean there is no customizability of spending conditions at all, and every output is just e.g. a public key, and every input is just a signature, and nothing else is possible.
Having this language at all just introduces features that wouldn't be achievable through other means. The simplest example is having coins that can only be spent when multiple people sign off on it(*), or only after a certain amount of time, or after some secret gets revealed. Together these are the basis for example for trustless escrows (where the escrow can't steal the coins), or for systems built on top like payment channels.
Perhaps your question is: why is this customizability of spending conditions not done using the language as the one the validation logic is written in? There are several reasons for this:
- It is essential that the outcome of evaluation of Bitcoin Script (or whatever alternative you're envisioning) only depends on data committed to by the transaction itself, or possibly in the blockchain it ends up in. Anything else is inviting risk of forks. For example, Scripts can (perhaps surprisingly) not observe the current time in any way. The (local) time at which validation is performed by various validators differs, so including the current time in Script could lead to a script that some validators accept and others reject, just by virtue of performing validation at different points in time. Bitcoin Script can however (indirectly) observe the timestamp of blocks in the blockchain, because this value is guaranteed to be identical for all validators. Imposing such strong restrictions on an existing language intended for general purpose programming is hard, and having a separate language for it makes it much easier to enforce this.
- Size matters. As a global consensus system, capacity is limited. Bandwidth and latency constraints of the slowest and least-well connected devices the system wishes to let participate set a bound on how much data can be included in the chain. One aspect of that size is how much data it takes to express typical conditions in the Script language (or whatever its replacement is). As we envision many transactions whose conditions for spending at least involve some form of signature check, it stands to reason that it should be very cheap to express these. In Bitcoin Script, the logic "require a signature on the current transaction with public key X" can be expressed in 2 bytes + the size of the public key. This would be much harder to accomplish using a general-purpose language.
- Computation cost, and predictability for that, matters. As the scripts included in transactions submitted to the network will be run and re-run by every validator (possibly ever), we care about the computational cost that validation entails for those validators, and specifically want an upper-bound on that cost. This means there needs to be some mechanism for stopping execution if it takes too long, or being able to determine ahead of time how long it's going to take.
- Not every piece of software that interacts with the blockchain or transactions is written in the same language. In Bitcoin, the currently most-used validation software is Bitcoin Core, which is written in C++, but it is far from the only wallet software, and these other wallets are written in a variety of languages. Using C++ for the scripting language would pretty much require all these implementations to have a C++ dependency. Given that C++ is a compiled language, it would additionally require access to a C++ compiler just to run the scripts received in blocks and transactions from the network. C++ isn't designed for such on-the-fly code updating, and using an abstraction to e.g. run it in a virtual machine or interpreter would negate whatever advantages existed to use the same language in the first place. The situation may be different for other languages of course, but the point remains that the goals for a language to write a validation engine is, and the goals for the language to write spendability conditions are wildly different, so there is little reason to want to cover both by a single language.
(*) There are techniques in modern cryptography to actually make a single public key that can only be spent when multiple people cooperate to spend it.