Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Infinite loop #364

Open
vmishenev opened this issue Nov 1, 2023 · 13 comments
Open

Infinite loop #364

vmishenev opened this issue Nov 1, 2023 · 13 comments

Comments

@vmishenev
Copy link

This issue is for discussion of the proposal to add an infinite loop for { ... }.
The full text of the proposal is here.

@Amejonah1200
Copy link

👀
Why does val result = for { break 42 } not return the type Int instead of Unit?

@thumannw
Copy link

thumannw commented Jan 5, 2024

Concerning infinite loop with break, what is the advantage of it being a Unit expression instead of just a statement?

@needlesslygrim
Copy link

I don't know if the keyword is still up for debate, but personally I think loop/repeat is a better choice. I see the reasoning in the full proposal is that it doesn't require introducing a new keyword, and that using while would make it look like the condition was missing. However, I personally have two questions:

  1. Doesn't for {} also have the same problem of looking like the condition is missing?
  2. Do loop or repeat not make better sense when read out loud? Saying for... print Hello World sounds a little strange, compared to normal use of for, for every item print item.name. I will admit that loop is also a little strange (although perhaps slightly better), loop... print Hello World, which is perhaps where repeat would be useful, but unlike for ( which I personally am familiar with because of Rust), is not used in any mainstream language I know of

@Amejonah1200
Copy link

I don't know if the keyword is still up for debate, but personally I think loop/repeat is a better choice. I see the reasoning in the full proposal is that it doesn't require introducing a new keyword, and that using while would make it look like the condition was missing

If the current version was Kotlin 0.x, I would've also suggested loop instead. Sadly, there are already code out there which might use loop or repeat (well, it exists in the std lib already!) and that code would break on upgrade. This is due to the fact that keywords have higher precedence than methods.

@needlesslygrim
Copy link

Ah, that makes sense. Maybe if there's ever a Kotlin 2.0 :^)

@mgroth0
Copy link

mgroth0 commented Feb 18, 2024

Yeah I dislike for {} because it gramatically makes no sense and is confusing. Love this idea in general but I wish it could be better english like repeat or even forever. Actually I wrote this method for myself a while ago:

inline fun forever(op: Op) {
    contract {
        callsInPlace(op, AT_LEAST_ONCE)
    }
    do op() while (true)
}

And I really like the way it looks, because it is crystal clear when you write forever {} that it is an endless loop.

@Amejonah1200
Copy link

The main benefit of such a "loop syntax" is: val result = for { break 42 }

As Kotlin already has the ability to create constructs like demonstrated by @mgroth0 above, if the ability of returning (more like breaking) a value isn't there, it is useless.

So I would propose to change this to loop constructs:

// returns either a string if broken or null if the condition is false or no more entries.
val result: String? = while(cond) { break "str" }
val result: String? = for(i in sequenceOf()) { break "str" }

The reason why a construct like

val result: Int = for (i in sequenceOf<Int>()) {} else 1

won't work, is because of these breaking cases:

for (i in sequenceOf<Int>()) if (true) else {} // is it `for ... else` or `if else`?
if (true) for (i in sequenceOf<Int>()) else {} // is it `if ... else` or `if { for ... else }`?

@Peanuuutz
Copy link

The reason why a construct like...

That's true. I guess in this case we would need to force the user to insert the brackets. Making them returning nullable is also an option. Either is OK to me.

@rebokdev
Copy link

rebokdev commented Mar 13, 2024

maybe instead of for we could use repeat { ... } ?
using for { ... } doesn't seem to make sense for me
as there's nothing to loop through
there should still be ability of break
the difference between normal repeat and
infinite one is easily noticeable so this shouldn't
be a problem to only have break in the infinite
one

@daniel-rusu
Copy link

daniel-rusu commented Jun 1, 2024

The proposal to use for { ... } goes in the opposite direction and reduces clarity rather than improving it as for is usually used in the context of "for each element" or "for elements indexed by". Using loop { ... } or repeat { ... } would improve clarity otherwise the plain old while (true) { ... } is clearest.

@needlesslygrim
Copy link

I do agree with this, and although it may be difficult to work around due to pre-existing code, I feel that introducing a new loop construct would be better. I recently tried Go, which uses for for all loops, which is a major mistake in my opinion (for the reasons outlined in this thread), but at least it is consistently strange, where in Kotlin while loops do exist, so only unifying endless loops and iterator loops is quite strange to me.

To fix the problems around pre-existing code, maybe some kind of compiler flag could be introduced to allow use of the loop construct, or perhaps 'editions' could be introduced, functioning similarly to how they do in Rust, although this would be a major undertaking.

@Peanuuutz
Copy link

If we can solve the compatibility issue, I'm glad to have loop instead.

More agressively, we can leave out while completely because we can combine loop and if to get both while and do..while!

@Gattag
Copy link

Gattag commented Dec 22, 2024

I know this idea gets floated every once in awhile and never gets anywhere, but I think that it would make more sense to improve Kotlin's ability to build such functionality in the language. ~~When I say that, I'm thinking about the idea of allowing operator overloading of break and continue. ~~ When I say that, I'm thinking of some mechanism to support break and continue on inlined lambdas.

The only real reason to introduce this as a language concept is to gain break and continue. And the only real reason to name it for and not to name it repeat is due to conflicts in the implementation of keywords in the Kotlin compiler and the pre-existence of functions with certain names in the standard library.

A repeat function with operator overloading of break and continue used on the receiver of an inlined lambda, that is defined in the standard library, would seem to solve the primary wants of this KEEP and improve Kotlin's ability to model other iterator-like things like forEach and what not. The downside to this approach being the need to introduce a receiver and requiring you to use this@ to reach the parent receiver.

Another approach that I'm starting to like more as I think about it, could be to support break and continue as special union error types that could be specified on inlined lambdas, or as flags on lambda types that automatically introduce the union type at the invocation site. The more and more I think about this, this method sounds really simple to implement in the compiler.

While I want the capabilities of this feature as much as the next guy, and often find myself introducing an arg-less repeat into wherever I have my random utils, but still longing for the ability to break the loop. I think that we need an arg-less repeat added to the standard library, that can use the feature I've just described in some way, and not a new for added to the language.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

10 participants