Page 1 of 1

ForEachReverse <-> ForEach with operating in reverse

Posted: Mon Jun 10, 2013 1:59 am
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

Re: ForEachReverse <-> ForEach with operating in reverse

Posted: Mon Jun 10, 2013 2:25 am
by 136
Or just allow "Step" to be used with "ForEach", so we can use "Step -1" to iterate backwards.

Re: ForEachReverse <-> ForEach with operating in reverse

Posted: Mon Jun 10, 2013 6:09 am
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

Re: ForEachReverse <-> ForEach with operating in reverse

Posted: Mon Jun 10, 2013 6:13 am
by STARGĂ…TE

Code: Select all

If LastElement(LinkList())
  Repeat
    Debug LinkList()
  Until PreviousElement(LinkList()) = #False
EndIf

Re: ForEachReverse <-> ForEach with operating in reverse

Posted: Mon Jun 10, 2013 2:12 pm
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.)

Re: ForEachReverse <-> ForEach with operating in reverse

Posted: Mon Jun 10, 2013 7:53 pm
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.

Re: ForEachReverse <-> ForEach with operating in reverse

Posted: Mon Jun 10, 2013 8:04 pm
by Fred
You could also use constants to enhance a bit the readibility:

Code: Select all

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

Re: ForEachReverse <-> ForEach with operating in reverse

Posted: Mon Jun 10, 2013 8:21 pm
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.

Re: ForEachReverse <-> ForEach with operating in reverse

Posted: Mon Jun 10, 2013 8:31 pm
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

Re: ForEachReverse <-> ForEach with operating in reverse

Posted: Mon Jun 10, 2013 8:38 pm
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:

Re: ForEachReverse <-> ForEach with operating in reverse

Posted: Tue Jun 11, 2013 5:44 am
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.

Re: ForEachReverse <-> ForEach with operating in reverse

Posted: Tue Jun 11, 2013 10:21 pm
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.

Re: ForEachReverse <-> ForEach with operating in reverse

Posted: Tue Jun 11, 2013 10:50 pm
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)

Re: ForEachReverse <-> ForEach with operating in reverse

Posted: Wed Jun 12, 2013 3:29 pm
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.