mIRC Homepage

Looping as an identifier

Posted By: SartenX

Looping as an identifier - 19/12/06 07:18 AM

Often when I'm writing a small script to do a specific thing, I need a simple counter to perform an action a given number of times. For example, if I want to echo the sum of all numbers from 1 to 10, I have to do:

Code:
/alias sum { var %sum,%n = $2 | while (%n) { inc %sum %n | dec %n } | return %sum }
//echo -a $sum(1,10)


It would be much nicer and easier to have an identifier, such as $for, that would let me just do:

Code:
//echo -a $for(%x,1,10,1,inc %sum %x) %sum


The reason for having this as an identifier is so that iterative tests can be done in a single command, such as:

Code:
$for(%x,1,$nick($active,0),2,if ($nick($active,%x) == Danny) return Danny is odd!)


would return "Danny is odd!" if Danny were in an odd-numbered position in the active window's nicklist.

The basic form I envision for such an identifier is similar to how for loops in C are often used.

Code:
$for(<variable>,<start>,<end>,<step>,<code>)


I managed to write an alias to provide this functionality, but it suffers from the fact that raw code cannot be passed in without formatting it correctly (either using $+ or $eval(<code>,0)). It also is worthless when trying to write small scripts for others, as in done in many help channels throughout the IRC community. Instead of using a clean for loop, we are stuck using external aliases, resorting to more complex while loops, abusing $regsubex, and running $findfile on large directories. My alias is as follows, and I hope it can be converted to a real built-in identifier.

Code:
alias for {
  set -l [ $1 ] [ $2 ]
  while ($eval($1,2) <= $3) {
    $eval($5,2)
    inc $eval($1,1) $4
  } 
}

This alias must be called by wrapping the parameters:
Code:
//echo -a $for($eval(%x,0),1,10,1,$eval(inc %sum %x ,0)) %sum
Posted By: Riamus2

Re: Looping as an identifier - 19/12/06 02:35 PM

Keep in mind that there is a mathematical way to do this.

Adding all digits 1-100:
Code:
//echo -a $calc((100 + 1) * (100 - 1 + 1) / 2)


(ending digit + beginning digit) * (ending digit - beginning digit + 1) / 2 = sum

You use a similar thing for using a step other than 1 (0-100 by 10):
Code:
//echo -a $calc((100 / 10) * (10 * (100 / 10) + 10) / 2)


This is Gauss's formula.

(ending digit / step) * (step * (ending digit / step) + step) / 2 = sum

(ending digit / step) = number of steps

Here's another example (0-20 by 2):
Code:
//echo -a $calc((20 / 2) * (2 * (20 / 2) + 2) / 2)



Note that this works from 0-N. It won't work from 10-N or something else unless you do more work. If you want to do a different starting number than 0, then you'll do the equation twice...

For 10-20 by 2:
Code:
//echo -a $calc(((20 / 2) * (2 * (20 / 2) + 2) / 2) - ((8 / 2) * (2 * (8 / 2) + 2) / 2))



(ending digit / step) * (step * (ending digit / step) + step) / 2 - ((beginning digit - step) / step) * (step * ((beginning digit - step) / step) + step) / 2 = sum

What you're doing is subtracting the sum of all the numbers prior to your starting number from the sum of the total.

You can make a $gauss identifier for this:
Code:
alias gauss {
  return $calc((($2 / $3) * ($3 * ($2 / $3) + $3) / 2) - ((($1 - $3) / $3) * ($3 * (($1 - $3) / $3) + $3) / 2))
}

USE: $gauss(beginning number,ending number,step)
EXAMPLE: $gauss(10,100,10)
NOTE: You should make sure that there is an even number of steps (1-4 step 2 wouldn't work well, but 0-4 step 2 would)
Posted By: Mardeg

Re: Looping as an identifier - 19/12/06 04:17 PM

There are a good many threads covering the issue of implementing for loops if you search for them.
Obligatory workaround for specified example:
Code:
//echo -a $iif($fline($active,Danny,1,1) & 1,Danny is odd!)
Posted By: Riamus2

Re: Looping as an identifier - 19/12/06 04:26 PM

For odd/even, it's as simple as:

$iif($calc(number % 2) == 1,EVEN,ODD)
Posted By: qwerty

Re: Looping as an identifier - 19/12/06 04:34 PM

It's simpler than that:
$iif(2 // number,EVEN,ODD)
or
$iif(number & 1,ODD,EVEN)

edit: typo
Posted By: jaytea

Re: Looping as an identifier - 19/12/06 04:36 PM

can be even simpler :P

Code:
$iif(2 // number,EVEN,ODD)
$iif(number & 1,ODD,EVEN)


edit: lol qwerty, great minds... ;O

anyway, if this for loop functionality was added it definitely shouldn't be in the form of an identifier. think of trying to use $findfile() to perform a series of commands, it's a pain, you'd have to use workarounds like another alias.. or /scon or /scid and then youd have to worry about escaping everything.. it all becomes messy

if it's ever added, the way that would be most suitable, imo, would be:

Code:
for (%i = 1, %i < 10, inc %i) {
  commands
}


as an example. inc %i could become %i ++ depending on how it would be implemented. of course this resembles a while loop, but can be used in cases where the condition need not be re-evaluated each iteration

but as an identifier? no thanks ;S
Posted By: starbucks_mafia

Re: Looping as an identifier - 19/12/06 04:46 PM

The identifier method has a good deal of possibility also, basically it (potentially) becomes an efficient iterating method like $*. As long as it was able to be nested within other identifiers it could be very useful. Note that there's nothing preventing for from being both a statement and an identifier.

I wouldn't want to see the %var++/-- operators added though. While they serve a useful purpose in some languages where pre/post-increment/decrement are meaningful because variables may be set in-line, it doesn't make any sense in mIRC scripting where they'd have to be a separate command anyway. That is unless things like %++blah would start being valid expressions in commands, which I'd hate to see.
Posted By: jaytea

Re: Looping as an identifier - 19/12/06 04:57 PM

Originally Posted By: starbucks_mafia
The identifier method has a good deal of possibility also, basically it (potentially) becomes an efficient iterating method like $*. As long as it was able to be nested within other identifiers it could be very useful. Note that there's nothing preventing for from being both a statement and an identifier.


oh yes, if it can be used inline to overcome the problems $* currently has, that would be really nice to see laugh i was thinking of it as related to $findfile() with its command parameter, but functionality like $* would make much more sense
Posted By: Sais

Re: Looping as an identifier - 19/12/06 05:10 PM

I think I'd rather see a 'foreach' style construct for iterating over elements of a list.

e.g.
Code:
foreach(%i,$chan(N)) { echo -a %i }


not sure how you'd format that nicely for parsing that, though.

You could also add something like Perl has - the '..' "operator" - so you can construct normal for loops like:

Code:
foreach $i (1..10) { print $i }




Posted By: Riamus2

Re: Looping as an identifier - 19/12/06 10:10 PM

Originally Posted By: qwerty
It's simpler than that:
$iif(2 // number,EVEN,ODD)
or
$iif(number & 1,ODD,EVEN)


Hm. I think I've seen someone mention // here before. I know what % is doing, but what is // as a mathematical term/operation? And what's &?
Posted By: jaytea

Re: Looping as an identifier - 19/12/06 11:36 PM

// isn't a mathematical operator, it's just a conditional operator on mirc meaning "is a factor of", so if (2 // N) checks if N is a multiple of 2

& represents a bitwise comparison, if (N & M), where M is some power of 2, is true if the bit with value M is turned on in N. so if (N & 1) is true if bit with value 1 (the first bit) of N is on, i.e. if its odd

Posted By: Riamus2

Re: Looping as an identifier - 20/12/06 12:41 AM

Heh, well factors are mathematical even if you don't use // in a mathematical formula. I was really just looking for the mathematical wording used for the character, which you provided. Thanks.
Posted By: SartenX

Re: Looping as an identifier - 20/12/06 01:10 AM

I don't remember which language it is, but there is one where // is the modulus operator...

I realize that all my examples could be worked around (especially the Gauss solution), but that's not the point. If you want to do a loop with a simple command, especially when done from the command line, you currently have to use a lot of worthless garbage.

I don't think including for loops makes ++ and -- necessary (I agree they'd suck)... I prefer to have the incrementing built into the loop, like in BASIC.

My biggest reason for having it as an identifier is so it could be used to make simple iterative tests easier. Like finding the first time another identifier matches a given criteria. Unlike $*, it should not execute the statement that contains it multiple times. It should only execute the command that's passed to it multiple times.

I like foreach structures... but how would mIRC determine what's an element in a list?
Posted By: Om3n

Re: Looping as an identifier - 20/12/06 01:37 AM

Originally Posted By: SartenX
I like foreach structures... but how would mIRC determine what's an element in a list?

Im guessing this would involve tokens, or lines in a buffer/file/socket/etc.
Posted By: Riamus2

Re: Looping as an identifier - 20/12/06 02:57 AM

I did see a good $for identifier a long time ago (years) in this forum. You might search for $for and set it to 5 years and see what you find. As for having one included, it wouldn't be a bad thing, but I wonder if it would be considering it's been requested off and on for years without being added. That doesn't mean it won't be someday, of course.
Posted By: SartenX

Re: Looping as an identifier - 20/12/06 05:51 AM

tokens would work... though it'd have to be something like $fortok(<variable>,<start>,<end>,<C>,<command>)

I searched... I didn't find anything...

EDIT: I searched again, and found old posts dealing with it. Mostly, there were objections relating to being able to do it with a while loop. One objection mentioned that a "$loop(<number>,<command>)" identifier wouldn't be useful because they almost always want to use multiple commands in the loop.

I wrote the scripts at http://paste.sarten-x.com/pastebin.pl?number=85 for fun, and all the ones that use $regsubex($str... could all be simplified greatly using a $for.

OTHER EDIT: It should be said that those scripts were written with the intent of using a single command to do the task. They also were written mostly after 3:00 AM.
Posted By: Riamus2

Re: Looping as an identifier - 20/12/06 02:38 PM

Hm... I could have sworn there was an actual FOR script written somewhere... but it's been at least a couple of years, so I don't remember anything else about it.

Anyhow, I agree with what people said regarding the use of WHILE. The only real difference between FOR and WHILE is that the increment is included in the FOR line, but not in the WHILE line. Sure, you could make an identifier for FOR rather than an actual looping command like FOR is usually seen (C++ for example) or like WHILE is here... but that just is more trouble, imo, than using it the way WHILE is used. And in that way, it isn't really helping anything.

But that's just me... I have never had an issue with using WHILE instead of FOR.
Posted By: Om3n

Re: Looping as an identifier - 20/12/06 10:55 PM

Dont worry, your not loosing your mind! There was a for script written at one point, iirc it was incomplete though (problems looping through lines in files i think? cant remember exactly), but i couldn't find it with search either. I know i replied to it so i even search through my own posts.
Posted By: Mpdreamz

Re: Looping as an identifier - 21/12/06 11:43 AM

Theres a dozen FOR scripts but they all lack multi line support. Its been argued by Khaled in the past that a while pretty much covers all your looping needs which is true in a way but a while can be quite annoying.
Code:
var %x = 0 , %y = 10
while (%x <= %y) { 
  ..
  inc %x
}

is a lot more annoying to type out then
Code:
for (%x=0,%y=10;%x <= %y;inc %x) { 
   ..
}


It just looks ALOT better the pure aesthetic reasons are enough for me to want it BAD.

I guess a foreach could work in mIRC. %0 specifies the N parameter
Code:
foreach($nick(#,%0)) { 
  ..
}


Where mIRC loops from 1 till $nick(#,0) rather then as long as it doesn't return NULL keeping hash tables in mind. The requirements for a foreachable identifier are simple there's an N parameter if N = 0 return the total amount of items. Which is basically how all mirc identifiers work.

Yes a while can do it all but other loop methods can cater to our scripting needs much more efficiently.
Posted By: Mpdreamz

Re: Looping as an identifier - 21/12/06 12:31 PM

Originally Posted By: SartenX
tokens would work... though it'd have to be something like $fortok(<variable>,<start>,<end>,<C>,<command>)

To include an end like that could be done with the foreach mentioned in my post above:
Code:
foreach($gettok(%var,%0,32),%i) { 
  if (%i == 5) break;
  ..
}
Posted By: Mpdreamz

Re: Looping as an identifier - 21/12/06 07:00 PM

i started fiddling with the idea of a scripted multiline for:
Code:
alias hello { 
  for (%x = 0;%x <= 5;+) $scriptline { 
    echo -a yay
    echo -a MultiLine! :D
  }
  echo -a Such a crappy for loop implementation :P
}
alias tok return $gettok($1,$2,32) 
alias for { 
  !noop $regex($1-,/\((.+?);(.+?);(.+)\)\s(\d+)/)
  set -l $tok($regml(1),1) $tok($regml(1),3)
  var %s = $regml(4) + 1 , %crement = $replace($regml(3),+,inc,-,dec) $tok($regml(1),1) , %condition = $regsubex($regml(2),/(\w+)$/,$calc($(\1,2) -2)))
  window -h @cool
  filter -fwgnr $+(%s,-999999) $qt($script) @cool /^\s*?}\s*?$/
  var %e = $tok($line(@cool,1),1) - 1 
  window -c @cool
  tokenize 32 %condition
  while ($($1,2) $2 $($3,2)) {  
    filter -fkgr $+(%s,-,%e) $qt($script) forcommands 
    %crement
  }
}
alias forcommands $1-


Its crappy coded, no error checking. Just to prove it is sorta possible smile
Posted By: Riamus2

Re: Looping as an identifier - 21/12/06 11:44 PM

Originally Posted By: Mpdreamz
Tis a lot more annoying to type out then

.
.
.

It just looks ALOT better the pure aesthetic reasons are enough for me to want it BAD.


That's a matter of opinion. I like the look of the while more than the for in your examples. It's similar to the idea that you can type a lot of commands on one line, but it is nicer looking and easier to read (imo) to have them on separate lines.
Posted By: Mpdreamz

Re: Looping as an identifier - 21/12/06 11:55 PM

Which is fair enough, to each their own smile
I did say "the pure aesthetic reasons are enough for me to want it BAD."
It doesn't hurt implementing.

my example was completely non spaced which would be sucky
Code:
for (%x = 0, %y = 10; %x <= %y; inc %x) { 
}


I would far from class this as putting alot commands on one line (something which is backwards to do) you merely instruct the parser to start looping on one line.
Posted By: Riamus2

Re: Looping as an identifier - 22/12/06 12:04 AM

Originally Posted By: Mpdreamz
I would far from class this as putting alot commands on one line (something which is backwards to do) you merely instruct the parser to start looping on one line.


What I meant by that is that you are putting all the variables and increment/decrement on a single line. As a while, it would look similar to:

Code:
var %c = 1, %i = 10 | while (%c <= i) { inc %i
  do stuff
}


Granted, that's really ugly, but it is just an example of what I meant by putting a lot of stuff on one line rather than separating it. And it is actually not very much longer than the for line (basically just the while included makes it longer -- or the length of while mixed with including var).

That example should do what the for would do EXCEPT that it would increment before doing the commands, rather than after. Of course, you can "fix" that from being a problem by using variables that are set to 0 and 9 (1 less). Yes, that's more troublesome, but it's just to illustrate my point.

As I have said, I don't care if FOR is added. I don't personally see a need for it, but it won't hurt me any if it is added for those who prefer it to using WHILE.
Posted By: SartenX

Re: Looping as an identifier - 25/12/06 04:29 PM

Riamus: I'm of the opinion that a for loop as a command would be nice, but very unnecessary. If you're going to be writing many lines anyway, a few more won't hurt. using a while is closer to assembly anyway. I realize that mIRC doesn't use ASM, but the logic's the same. All looping structures are identical at the logical level.

I'm just looking for an easy way to do easy things.

Mpdreamz: A local variable would work well. I was thinking like perl, where it just knows how much data is available. Or maybe I just wasn't thinking...

Merry Christmas, y'all!
Posted By: astigmatik

Re: Looping as an identifier - 15/02/07 03:04 PM

I prefer this:

Code:
foreach %nick ($nick(#, rovha)) {
  echo -a %nick
}

foreach %address ($ial(#).all) {
  echo -a %address
}

foreach %line (@window) {
  echo -a %line
}

foreach %line ($readAll(readme.txt)) {
  echo -a %line
}

foreach %ini ($ini(file.ini).headers) { }

foreach %ini_items ($ini(file.ini, header).items) { }

foreach %key, %value ($hashtable(name)) {
  echo -a %key = %value
  ; automatically extracting the $hget(name, key) and its value, python dict style
}


Originally posted at http://www.mircscripts.org/forums.php?cid=4&id=157414#157414
Posted By: hixxy

Re: Looping as an identifier - 15/02/07 06:15 PM

That doesn't match any existing mIRC syntax. I think it's a bad idea to bring in things like that. There should be a level of consistency.

Code:
foreach (%nick,$nick($chan,rovha)) {

}


The above would at least be similar to what exists already. To be honest though, I don't see the point in a foreach loop for mIRC. foreach is really something I'd only consider useful in an OOP language.

PS.
In the above example, how would mIRC know where to put to put the incrementation variable? ($nick($chan,N,rovha))
Unless you're suggesting that $nick($chan,rovha) return an array/collection, which would need to be implemented first.
Posted By: astigmatik

Re: Looping as an identifier - 16/02/07 04:06 AM

Yes I'm suggesting that those identifiers would return some kind of array collection that is only accessible with the foreach loop. See the ms.org posting for updates. Something like this:

Code:
foreach ($read(file.txt, not_sure_about_second_parm)) {
  $v1 would contain the line being read
}

foreach ($nick(#, rovha)) {
  $v1 would be the nick
}
Posted By: hixxy

Re: Looping as an identifier - 16/02/07 10:44 AM

That makes a little more sense.

I think that would require almost every identifier to be rewritten for the foreach loop though - if so, I think there's slim chance of that happening.
© 2021 mIRC Discussion Forums