ForEachReverse <-> ForEach with operating in reverse

Got an idea for enhancing PureBasic? New command(s) you'd like to see?
Savapo
New User
New User
Posts: 8
Joined: Sun Jun 02, 2013 1:55 am

ForEachReverse <-> ForEach with operating in reverse

Post by Savapo »

Hello,

Please, could you add this functionality to simplify writing programs ?

Thank you.

Code: Select all

NewList List()

AddElement(List())
List()=1

AddElement(List())
List()=2

AddElement(List())
List()=3

; ------

ForEachReverse List() ; <- *** Here, new instruction ***

  Debug List()        ; -> 3
                      ; -> 2
                      ; -> 1
Next

; ------

ForEach List()

  Debug List()        ; -> 1
                      ; -> 2
                      ; -> 3
Next
136
New User
New User
Posts: 2
Joined: Fri Jun 07, 2013 11:02 am

Re: ForEachReverse <-> ForEach with operating in reverse

Post by 136 »

Or just allow "Step" to be used with "ForEach", so we can use "Step -1" to iterate backwards.
User avatar
Bisonte
Addict
Addict
Posts: 1305
Joined: Tue Oct 09, 2007 2:15 am

Re: ForEachReverse <-> ForEach with operating in reverse

Post by Bisonte »

not necessary ....

Code: Select all

NewList LinkList()

AddElement(LinkList()) : LinkList() = 1
AddElement(LinkList()) : LinkList() = 2
AddElement(LinkList()) : LinkList() = 3

ForEach LinkList()
  Debug LinkList()
Next

Debug "-----"
; This ....
MaxIndex = ListSize(LinkList()) - 1
LastElement(LinkList())
While MaxIndex > -1
  Debug LinkList()
  PreviousElement(LinkList())
  MaxIndex - 1
Wend

Debug "-----"
; Or this...

LastElement(LinkList())
MaxIndex = ListIndex(LinkList())

For i = MaxIndex To 0 Step -1
  SelectElement(LinkList(), i)
  Debug LinkList()
Next i
PureBasic 6.21 (Windows x64) | Windows 11 Pro | AsRock B850 Steel Legend Wifi | R7 9800x3D | 64GB RAM | RTX 5080 | ThermaltakeView 270 TG ARGB | build by vannicom​​
English is not my native language... (I often use DeepL.)
User avatar
STARGÅTE
Addict
Addict
Posts: 2226
Joined: Thu Jan 10, 2008 1:30 pm
Location: Germany, Glienicke
Contact:

Re: ForEachReverse <-> ForEach with operating in reverse

Post by STARGÅTE »

Code: Select all

If LastElement(LinkList())
  Repeat
    Debug LinkList()
  Until PreviousElement(LinkList()) = #False
EndIf
PB 6.01 ― Win 10, 21H2 ― Ryzen 9 3900X, 32 GB ― NVIDIA GeForce RTX 3080 ― Vivaldi 6.0 ― www.unionbytes.de
Lizard - Script language for symbolic calculations and moreTypeface - Sprite-based font include/module
User avatar
Tenaja
Addict
Addict
Posts: 1959
Joined: Tue Nov 09, 2010 10:15 pm

Re: ForEachReverse <-> ForEach with operating in reverse

Post by Tenaja »

Bisonte wrote:not necessary ....
Most commands are not necessary, including the original ForEach, as well as most iteration commands.
The o/p referenced simplifying writing; just look how much more elegant this is (with two PB keywords not counting the iteration code)...

Code: Select all

ForEach LinkList()
  Debug LinkList()
Next
Compared to this (with six PB keywords)...

Code: Select all

If LastElement(LinkList())
  Repeat
    Debug LinkList()
  Until PreviousElement(LinkList()) = #False
EndIf
...Which is clearly the most elegant solution so far. (Especially if your loop happens to insert elements.)

If Fred adds a Step, it won't be much worse than the current ForEach, but if he chooses a ForEachReverse command, it will be just as elegant as the current ForEach. (And likely easier to implement, but less flexible.)
BorisTheOld
Enthusiast
Enthusiast
Posts: 542
Joined: Tue Apr 24, 2012 5:08 pm
Location: Ontario, Canada

Re: ForEachReverse <-> ForEach with operating in reverse

Post by BorisTheOld »

Bisonte wrote:not necessary ....
While I agree the proposed feature is not necessary, it's certainly a lot clearer than your long solution.

I'm very much in favour of readable code, especially when the time comes for someone to maintain it many years from now.

We've set up many macros to remove the opacity from PB's commands. For example, which is more readable?

Code: Select all

    DisableGadget(#Gadget, 0)
    HideGadget(#Gadget, 0)

or

    EnableButton(#Gadget)
    ShowButton(#Gadget)
We currently use over 400 macros for supporting OOP, dynamic libraries, and readable code. These are all set up as custom keywords in the IDE.
For ten years Caesar ruled with an iron hand, then with a wooden foot, and finally with a piece of string.
~ Spike Milligan
Fred
Administrator
Administrator
Posts: 18153
Joined: Fri May 17, 2002 4:39 pm
Location: France
Contact:

Re: ForEachReverse <-> ForEach with operating in reverse

Post by Fred »

You could also use constants to enhance a bit the readibility:

Code: Select all

DisableGadget(#Gadget, #False)
HideGadget(#Gadget,  #False)
Little John
Addict
Addict
Posts: 4777
Joined: Thu Jun 07, 2007 3:25 pm
Location: Berlin, Germany

Re: ForEachReverse <-> ForEach with operating in reverse

Post by Little John »

Fred wrote:You could also use constants to enhance a bit the readibility:

Code: Select all

DisableGadget(#Gadget, #False)
HideGadget(#Gadget,  #False)
Absolutely.

And you can even use more meaningful names for the gadget constants, e.g.:

Code: Select all

DisableGadget(#ButtonOK, #False)
HideGadget(#ButtonCancel, #False)
I can't see any problem with readability here at all.
BorisTheOld
Enthusiast
Enthusiast
Posts: 542
Joined: Tue Apr 24, 2012 5:08 pm
Location: Ontario, Canada

Re: ForEachReverse <-> ForEach with operating in reverse

Post by BorisTheOld »

Fred wrote:You could also use constants to enhance a bit the readibility:

Code: Select all

DisableGadget(#Gadget, #False)
HideGadget(#Gadget,  #False)
Yes, we thought about that, but decided it would still be confusing since the important information is at the end of the parameter list. When reading through a complex source listing, the eye tends to follow the commands, not scan every parameter looking for special situations.

An alternative might be to set up meaningful constants, such as:

Code: Select all

#HideGadget = 1
#ShowGadget = 0
#DisableGadget = 1
#EnableGadget = 0

DisableGadget(#Gadget, #EnableGadget)
HideGadget(#Gadget,  #ShowGadget)
But we felt this was still a little like having to click on "Start" in order to stop Windows. We went with meaningful macro names so there was no confusion about the type of gadget being referenced.

Code: Select all

Macro ShowButton (GadgetNumber)
  HideGadget(GadgetNumber, 0)
EndMacro

Macro ShowString (GadgetNumber)
  HideGadget(GadgetNumber, 0)
EndMacro

etc
For ten years Caesar ruled with an iron hand, then with a wooden foot, and finally with a piece of string.
~ Spike Milligan
User avatar
skywalk
Addict
Addict
Posts: 4210
Joined: Wed Dec 23, 2009 10:14 pm
Location: Boston, MA

Re: ForEachReverse <-> ForEach with operating in reverse

Post by skywalk »

I agree that my mind tends to support positive logic more readily.
And why so many characters to say 0 or 1?
I think it is universally understood what 0 means in these contexts.
Especially if you have a procedure with multiple boolean parameters to enter. :idea:
The nice thing about standards is there are so many to choose from. ~ Andrew Tanenbaum
BorisTheOld
Enthusiast
Enthusiast
Posts: 542
Joined: Tue Apr 24, 2012 5:08 pm
Location: Ontario, Canada

Re: ForEachReverse <-> ForEach with operating in reverse

Post by BorisTheOld »

skywalk wrote:And why so many characters to say 0 or 1?
I think it is universally understood what 0 means in these contexts.
My intent is to simplify and clarify, not find a long way of specifying 0 or 1. In fact, my approach avoids having to specify the 0 or 1.

Hence, the statement:

Code: Select all

ShowButton(#Gadget)
actually uses fewer characters, and more clearly indicates what is being accomplished, than:

Code: Select all

HideGadget(#Gadget, 0)
PB is a powerful language, but some of its command names don't work well in English. So we restructure some of the commands to make our code more readable and self documenting. We modify PB commands to use more traditional English word pairings, such as: add/delete, begin/end, start/stop, attach/detach, capture/release, create/destroy, etc.

For example, in PB, "ButtonGadget" creates a button, but "FreeGadget" deletes it. The problem here is that the word "Free" does not imply destruction. Something can be free but still exist. Also, does "FreeGadget" mean create a gadget of type "Free"? So, instead, we use the following constructs:

Code: Select all

CreateButton(#Gadget, .........)
DestroyButton(#Gadget)
All programming languages have quirky syntax. I've found that making a few changes, using macros, can simplify the coding process and make maintenance much easier in the future. I've also found that self-documenting commands obviate the need for additional comments to explain the code.
For ten years Caesar ruled with an iron hand, then with a wooden foot, and finally with a piece of string.
~ Spike Milligan
User avatar
Tenaja
Addict
Addict
Posts: 1959
Joined: Tue Nov 09, 2010 10:15 pm

Re: ForEachReverse <-> ForEach with operating in reverse

Post by Tenaja »

ShowButton(#Gadget)
I have made similar macros, especially when I first started using PB. The lack of F1-Help support has reduced that significantly in the past couple years though.
Neil
Enthusiast
Enthusiast
Posts: 198
Joined: Wed Feb 29, 2012 8:04 am
Location: Melbourne, AUS

Re: ForEachReverse <-> ForEach with operating in reverse

Post by Neil »

BorisTheOld wrote:
For example, in PB, "ButtonGadget" creates a button, but "FreeGadget" deletes it. The problem here is that the word "Free" does not imply destruction. Something can be free but still exist. Also, does "FreeGadget" mean create a gadget of type "Free"? So, instead, we use the following constructs:

Code: Select all

CreateButton(#Gadget, .........)
DestroyButton(#Gadget)
All programming languages have quirky syntax. I've found that making a few changes, using macros, can simplify the coding process and make maintenance much easier in the future. I've also found that self-documenting commands obviate the need for additional comments to explain the code.
Hi Boris,

Very interesting post (as usual !!).

I think I'll start adding some of these type of macros.

A particular command that took me ages to find was:

Code: Select all

DisableGadget(Button_Collect_Files,#True)
I was looking for something like:

Code: Select all

SetGadgetActive(Button_Collect_Files,#True)
The language I am usually using would have:
!This.Button_Collect_Files.Active = t or f
So I was looking for "Active" !!

So I guess now I can have:

Code: Select all

SetGadgetActive(Button_Collect_Files,[#True,#False])
or even (using your logic):

Code: Select all

SetGadgetActive(Button_Collect_Files)
SetGadgetInActive(Button_Collect_Files)
BorisTheOld
Enthusiast
Enthusiast
Posts: 542
Joined: Tue Apr 24, 2012 5:08 pm
Location: Ontario, Canada

Re: ForEachReverse <-> ForEach with operating in reverse

Post by BorisTheOld »

Neil wrote:Very interesting post (as usual !!).
Thanks - I'm glad you found it useful.

I'm an old mainframe Assembler programmer who very quickly learned the benefits of using macros to clarify code and increase coding efficiency -- all without adding CPU cycles to the code.

Here's a PB example. It's a macro for destroying a class instance, plus a couple of other general purpose macros.

Code: Select all

Macro DestroyObject (bvsObjectName)
  If IsObject(bvsObjectName)
    bvsObjectName = bvsObjectName\funDestroy()
  EndIf
EndMacro
;
Macro IsObject (bvsDataParmName)
  bvsDataParmName <> 0
EndMacro
;
Macro Me
  *Self
EndMacro
;
;------ destroy an object in the current class
;
  DestroyObject(Me\oObjectName)
;
;------ this is the expanded code that executes the object's "Destroy" method
;
  If *Self\oObjectName <> 0
    *Self\oObjectName = *Self\oObjectName\funDestroy()
  EndIf
This is a simple example that shows how much coding can be saved and how much clearer the code is.

Judicious use of macros saves huge amounts of coding effort, simplifies the code, reduces the chance of making errors, and makes maintenance easier.

By the way, we use Polish notation in our code. So "oObjectName" refers to an object pointer named "ObjectName". And "funDestroy" refers to a function procedure named "Destroy". In our code, functions return a value, but subroutines don't.

In the above example, if the object is successfully destroyed then the object pointer is set to zero.
For ten years Caesar ruled with an iron hand, then with a wooden foot, and finally with a piece of string.
~ Spike Milligan
Post Reply