05-07-2022, 02:04 PM | #1 |
Grand Sorcerer
Posts: 11,757
Karma: 7029857
Join Date: Jan 2010
Location: Notts, England
Device: Kobo Libra 2
|
Request for opinion: a template while loop
I have been thinking about adding a while loop construct to the template language. This would permit looping based on a count or some test between two lists. The construct would be what one would expect:
Code:
while expr do <<stuff>> od Code:
while expr: <<stuff>> od The problem: this construct would for the first time permit infinite loops in the template language. A template infinite loop would freeze the GUI and be nearly impossible to fix because the user could never get past the loop to the editor. One possible fix is to limit the number of iterations to something, perhaps 1000. The loop would exit if this limit is hit. That would permit getting to the editor to fix it, albeit with some delays. This solution opens the door to a language construct to specify the limit, for example: Code:
while expr limit <numeric expression> do <<stuff>> od An alternate construct would be to avoid the problem by not using a while loop but instead require a counting for loop and a break statement, such as: Code:
for var range N to M: <<stuff>> if <something> then break fi; <<stuff>> rof Thoughts on
|
05-08-2022, 02:00 AM | #2 |
creator of calibre
Posts: 43,920
Karma: 22669818
Join Date: Oct 2006
Location: Mumbai, India
Device: Various
|
I vote for a for loop. Since the language is meant for newcomers to programming to be able to use, its safer.
|
Advert | |
|
05-08-2022, 09:06 AM | #3 |
Grand Sorcerer
Posts: 24,906
Karma: 47303748
Join Date: Jul 2011
Location: Sydney, Australia
Device: Kobo:Touch,Glo, AuraH2O, GloHD,AuraONE, ClaraHD, Libra H2O; tolinoepos
|
I'd go with the for loop as well. I've seen the condition on while loops mess up far to many times.
|
05-08-2022, 03:12 PM | #4 |
Custom User Title
Posts: 8,710
Karma: 62000001
Join Date: Oct 2018
Location: Canada
Device: Kobo Libra H2O, formerly Aura HD
|
As someone who's good at breaking things, the for loop seems a lot more difficult to break.
|
05-08-2022, 05:06 PM | #5 |
Bibliophagist
Posts: 35,839
Karma: 145624992
Join Date: Jul 2010
Location: Vancouver
Device: Kobo Sage, Forma, Clara HD, Lenovo M8 FHD, Paperwhite 4, Tolino epos
|
|
Advert | |
|
05-08-2022, 05:18 PM | #6 |
Custom User Title
Posts: 8,710
Karma: 62000001
Join Date: Oct 2018
Location: Canada
Device: Kobo Libra H2O, formerly Aura HD
|
|
05-08-2022, 05:39 PM | #7 |
Bibliophagist
Posts: 35,839
Karma: 145624992
Join Date: Jul 2010
Location: Vancouver
Device: Kobo Sage, Forma, Clara HD, Lenovo M8 FHD, Paperwhite 4, Tolino epos
|
|
05-10-2022, 03:02 AM | #8 |
Custom User Title
Posts: 8,710
Karma: 62000001
Join Date: Oct 2018
Location: Canada
Device: Kobo Libra H2O, formerly Aura HD
|
Could this be a simple use case for a while loop?
I was thinking something like this in an action chain: Code:
while select($identifiers, 'mobi-asin') do columnupdate_identifiers_amazon() od Last edited by ownedbycats; 05-10-2022 at 03:23 AM. |
05-10-2022, 04:39 AM | #9 | |
Grand Sorcerer
Posts: 11,757
Karma: 7029857
Join Date: Jan 2010
Location: Notts, England
Device: Kobo Libra 2
|
Quote:
|
|
05-12-2022, 10:46 AM | #10 |
Grand Sorcerer
Posts: 11,757
Karma: 7029857
Join Date: Jan 2010
Location: Notts, England
Device: Kobo Libra 2
|
I am implementing the for/range loop.
Syntax: Code:
for_expr ::= for_list | for_range for_list ::= 'for' identifier 'in' list_expr [ 'separator' separator_expr ] ':' expression_list 'rof' for_range ::= 'for' variable 'range' [ start_expr 'to' ] stop_expr [ 'limit' limit_expr ] ':' expression_list 'rof' Code:
program: res = ''; for i range 0 to strlen($title): c = substr($title, i, i+1); res = strcat(res, if mod(i, 2) == 0 then uppercase(c) else c fi) rof The limit specified the maximum number of loop iterations allowed. It is set to 1000 if omitted. |
05-12-2022, 09:35 PM | #11 | |
Grand Sorcerer
Posts: 24,906
Karma: 47303748
Join Date: Jul 2011
Location: Sydney, Australia
Device: Kobo:Touch,Glo, AuraH2O, GloHD,AuraONE, ClaraHD, Libra H2O; tolinoepos
|
Quote:
Except that I really don't like the handling of the range. Firstly, I will never remember the upper limit rules. I will automatically write "strlen($title) - 1" and wonder why it doesn't work properly. I would always expect that the range to handle both the start number and the last number. |
|
05-13-2022, 04:30 AM | #12 | |
Grand Sorcerer
Posts: 11,757
Karma: 7029857
Join Date: Jan 2010
Location: Notts, England
Device: Kobo Libra 2
|
Quote:
We start with the fact that like in python, ranges in the template language are 'i = start' to 'i < stop'. Consider list slices and substrings. Why should a loop from 1 to strlen(x) do something different than substr(x,1,strlen(x)) or sublist(x,1,4,',')? We then should consider previous knowledge, which argues for doing what some other language already does. There are three basic formulations that I remember:
Any one of the following works for me:
Using this scheme the for statement syntax would be mostly unchanged. The only change is to add the 'limit' clause. Code:
for_expr ::= 'for' identifier 'in' list_expr [ 'separator' separator_expr ] [ 'limit' limit_expr ] ':' expression_list 'rof' |
|
05-13-2022, 05:06 AM | #13 |
creator of calibre
Posts: 43,920
Karma: 22669818
Join Date: Oct 2006
Location: Mumbai, India
Device: Various
|
From a usability perspective I like range, however, range has th eissue of performance, which is why though the initial python implementation of range returned a list of numbers, in later versions it was changed to return an iterator over numbers.
|
05-13-2022, 05:41 AM | #14 | |
Grand Sorcerer
Posts: 11,757
Karma: 7029857
Join Date: Jan 2010
Location: Notts, England
Device: Kobo Libra 2
|
Quote:
Code:
program: for i in range(1, 10, 1) limit 1000: <<something>> rof Code:
generator = (str(j) for i,j in enumerate(range(start, stop, step)) if i < limit) for lv in generator: user_vars[loop_var] = lv <<execute the block>> It might be better from an error reporting standpoint not to check the limit in the generator but instead use an enumerate() when looping, checking the limit explicitly, and raising an exception if it is exceeded. Something like: Code:
generator = (str(j) for j in range(start, stop, step)) for count, lv in enumerate(generator): if count > limit: raise (ERROR) user_vars[loop_var] = lv <<execute the block>> |
|
05-13-2022, 07:27 AM | #15 |
creator of calibre
Posts: 43,920
Karma: 22669818
Join Date: Oct 2006
Location: Mumbai, India
Device: Various
|
You could have both, in the for loop context make range special and everywhere else have it return a list. Reporting an error when limit is exceeded seems better to me.
If you do have range be a special function in the for context, you can statically determine when limit is excedded instead of checking on every iteration. |
|
Similar Threads | ||||
Thread | Thread Starter | Forum | Replies | Last Post |
Template: Converting a search & replace into a template | ownedbycats | Library Management | 11 | 03-26-2021 04:32 AM |
Request for comments: new template language operations | chaley | Library Management | 3 | 02-27-2021 12:09 PM |
Request: Match Calibre Filename template recipe | cbook7 | Library Management | 10 | 06-05-2020 05:11 AM |
Request: template-making assistance for column built from other columns | iienderii | Library Management | 9 | 04-04-2016 10:27 PM |
Request for Feedback on E-book Web Template | andreasw | Writers' Corner | 5 | 05-14-2011 12:34 AM |