-
-
Notifications
You must be signed in to change notification settings - Fork 2.7k
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
Proposal: Generator / Iterator Syntactic Sugar #5331
Comments
If I understand correctly, the problem is that const MyTokenizer = struct {
inner: Tokenizer,
delimiter: []const u8,
pub fn init(parse_string: []const u8, delimiter: []const u8) MyTokenizer {
return .{
.inner = Tokenizer.init(parse_string),
.delimiter = delimiter,
};
}
pub fn next(self: *MyTokenizer) ?[]const u8 {
return self.inner.next(self.delimiter);
}
}; var tokenizer = MyTokenizer.init("device.title", ".");
while (tokenizer.next()) |token| {
// Utilize token...
} Now the iteration site is using only the information that's necessary. |
The issue I was more so getting at is that the iterable instance is not functionally constant. Perhaps I'm trying to ad-hoc in too many assumptions given to me by other languages, but it's generally not ideal to expose things that shouldn't be mutated beyond the way they're designed to be interfaced.
|
I've been taking a closer look at |
@kayomn You cannot do something like |
This is kind of just a thing with Zig, we technically have See #3110 for a long discussion on this. My own opinion is that iteration is one of those things that Zig kind of makes a mess out of, mainly because I think its a tad odd to use a bunch of optional syntax to do iteration with while loops. Anyway if you don't want to leak variables around you just have to wrap stuff in curly braces to create scopes. So doing a C style for loop in Zig would be like this: // Code
for (int i = 0; i<20; i++){
for (int j = 0; j<20; j++{
// Do stuff with i and j
}
}
// More Code // Code
{
var i = 0;
while (i < 20):(i+=1){
var j = 0;
while (j < 20):(j+=1){
// Do stuff with i and j
}
}
}
// More code (i and j are not leaked) |
I don't necessarily think that's exposing internals unnecessarily. While iterators in many languages have their |
I think I understand what you mean; there is always a mutable alias to the iterator available within the body of the loop. You cannot get around this currently with scope blocks, so code within the loop might do nasty things with the state of the iterator. maybe something like this would be appropriate: while ( { Tokenizer.init("device.name") }.next(".")) |token| {
// ...
} where the expression in |
Yeah that's pretty much my thoughts @jessrud . I wouldn't say I'm a particularly strong advocate of functional programming, but it's nice to have something that is "functionally const" to the rest of the program due to how it implicitly scopes itself. |
Do you mean |
Although #3110 was a much broader proposal than this one, I think the comment Andrew left as he closed that one is relevant here too.
One thing is clear, we can't make IMO the most realistic proposal addressing this problem is #8019 (expression-scoped variables). |
I know, I know, but hear me out; I have an argument to be made beyond "it looks pretty".
So consider the following premise: there is a need to generatively sub-string an input string according to some delimiters. In this scenario, we want to split up the string
"device.title"
into"device"
and"title"
.The initial tact I took for solving this was:
However, I was unhappy with the resulting code and I decided to see if there were any other ways of expressing this in Zig by looking around online, and I stumbled upon #809 .
So basically the gripe I have is that the above example is that it exposes state in the callsite that should not be managed by the user of
Tokenizer
.C# of course implements the IEnumerable intrinsic behavior, which is far from ideal, and D has "voldemort
struct
s" which can useopApply
, an operator overload, which is in my opinion far worse for self-documenting how the hell it iterates.I'm not sold on the idea of using either solutions that C# or D bring forth because of the above reasons mentioned, but I do think there needs to be a way to compound the initialization and iterative behavior into a single statement so as to be able to limit the scope of the generator / iterator and better define user-exposed APIs in a way that's also arguably more function at no cost to overhead.
Interested to hear other's thoughts on this though as this has been raised before for similar reasons.
The text was updated successfully, but these errors were encountered: