Thanks for the counter-example! I suppose you're talking about this piece of code
with(service) { connect(); sendData(data); disconnect() }
Agree, it becomes uglier with a nullable service. But from the reader point of view both ?.run and ?.let are nearly indistinguishable, and while run name conflicts with many existing Java libraries and the semantics of running something in the context of a nullable object is less common, "let" doesn't have that problem, that's why I advocating for not using "run" to reduce the cognitive load and probability of error.
Take a look at ?.let instead of ?.run
service?.let { it.connect(); it.sendData(data); it.disconnect() }
Almost the same. But what's important to me in this hypothetical example is the fact that something at the very core of the function is nullable. I'd try to avoid that fact at all cost, and if it's impossible I would indeed put a guard clause in front to make it as clear as possible: NO further action can be done if the service is not available. So yes, the guard clause would stick out like a sore thumb, but it's by design. And I would recommend that over run/let/with.
Or did you mean a similar structure but with a less critical object? Let me know if you have an example.