#'optional while' exit first iteration

1 messages · Page 1 of 1 (latest)

zinc lichen
#

Running while (arg_iterator.next()) is there some way to run code when the while loop doesn't run, because the first call of next returns null?

#

I guess the equivalent of a size == 0 check on an array but for iterators.

buoyant breach
#

you want it to run some other code when next returns null, but then continue back and check next again?

#

what is the condition for it leaving this loop

#
while (true) {
  if (arg_iterator.next()) ...
  else {
    // other code
  }
}

could work

zinc lichen
#

in my case telling the user to specify an argument

buoyant breach
#

you can just call next before the while loop

zinc lichen
#

So putting it in a variable and mutating it in the loop?

#

Hmm for some reason I thought that would be way more code

#
var maybe_next_arg = arg_iterator.next();
if (maybe_next_arg == null) {
    try stderr.print("Specify a parameter", .{});
    try stderr.flush();
    return 1;
}

while (maybe_next_arg) |next_arg| {
  // ...
  maybe_next_arg = arg_iterator.next();
}

This works, but it checks maybe_next_arg twice.

#

Is that fine / what you meant, or is there a better way

#

Btw I'm completely fine with this but knowing Zig maybe there's some syntax/pattern I missed

tender cloud
#

It sounds like you're looking for while (it.next()) |arg| {} else {}

zinc lichen
#
while (arg_iterator.next()) |next_arg| {
  // ...
} else {
  try stderr.print("Specify a parameter", .{}); // always runs, even if there was a previous parameter
  try stderr.flush();
  return 1;
}
tender cloud
#

Okay, I'm understanding your use case a bit more. You're right, that wouldn't be appropriate.

tender cloud
neon mesa
#

could you do something like

const maybe = arg_iterator.first();
if (maybe != null) {
    ...
}

while (arg_iterator) |arg| : (arg_iterator.next()) {
    ...
}
tender cloud
#

Actually, I just realized not all the iterators have peek(), never mind lol

zinc lichen
#

Would've been appropriate yeah

zinc lichen
#
var maybe_next_arg = arg_iterator.next();
if (maybe_next_arg == null) {
    try stderr.print("Specify a parameter", .{});
    try stderr.flush();
    return 1;
}

while (maybe_next_arg) |next_arg| : (maybe_next_arg = arg_iterator.next()) {
  // ...
}

It could be this indeed, but it has the same problem

#

In that the first maybe_next_arg is being checked twice, once in the if statement and once in the first run of the while loop

sharp ore
#

you could

var ran = false;
while (iter.next()) |arg| {
 ran = true;
 //...
}
if (!ran) //...
#

if you want to do it beforehand
you can just copy the body of the loop into an if

if (iter.next()) |arg| {
//do arg stuff
} else {
//...
}
while (iter.next()) |arg| {
// also do arg stuff
}
#

that doesnt check it twice

zinc lichen
#

Fair, thanks for the suggestions! I realized a do {} while would do the job nicely here, if Zig had it:

var maybe_next_arg = arg_iterator.next();
if (maybe_next_arg == null) {
    try stderr.print("Specify a parameter", .{});
    try stderr.flush();
    return 1;
}

do {
  // Doesn't check maybe_next_arg the first iteration
} while (maybe_next_arg) : (maybe_next_arg = arg_iterator.next());
frosty arch
#
if (it.next()) |arg0| {
    var arg = arg0;
    while (true) : (arg = it.next() orelse break) {
        // loop body
    }
    // reached when some args
} else {
    // reached when 0 args
}
#

typed this up on my phone, haven't verified whether it works