Discussion:
BASIC (and Horizon)
(too old to reply)
Simon Clubley
2024-01-29 18:27:36 UTC
Permalink
$ set response/mode=good_natured
Don't be too hard on David, Dan. He still likes to use line numbers
in his BASIC code... :-)
That is a filthy slander ...
Line numbers can be used in place of labels for GoTo statements, which you'll
also probably also slander. But they can be useful. Other than that, line
numbers can be useful for appending boiler plate code to a program. Line
numbers are used in handling error exceptions and handling.
Your implication that I use numbers on every line is just false.
$ set response/mode=good_natured

Er, David, where do I say _every_ line ? Or is that a guilty conscience
that's reading something above which isn't there ? :-)

It was a reference to the last time you posted a bit of BASIC code and
it was pointed out it could be written much more cleanly using structured
control loops.

Someone (Arne IIRC) posted some BASIC code using structured control
loops and I don't remember you being too impressed by the different
coding style, even though to me, Arne's version looked a lot cleaner.
On Error GoTo 32000
Ahhh, what's the use, you're probably just laughing ...
$ set response/mode=angry

On the plus side, and to take the opportunity to vent my anger at something
that I get more angry about whenever more details are revealed, at least
you know how to reverse the sign of a variable without having to write a
function to do it. :-( :-(

See:

https://news.ycombinator.com/item?id=38926582

Original reference:

https://www.postofficehorizoninquiry.org.uk/evidence/fuj00080690-report-eposs-pinicl-task-force

See page 17 onwards of the PDF. :-(

Innocent people went to jail because of the system this code is
a part of, and because of the coverup around it, and it took
a TV drama to really get things moving. :-(

So, yes, I may make fun of your line numbers, but at least you most
certainly know what you are doing, unlike the above people.

Simon.
--
Simon Clubley, ***@remove_me.eisner.decus.org-Earth.UFP
Walking destinations on a map are further away than they appear.
Arne Vajhøj
2024-01-30 00:06:18 UTC
Permalink
Post by Simon Clubley
On the plus side, and to take the opportunity to vent my anger at something
that I get more angry about whenever more details are revealed, at least
you know how to reverse the sign of a variable without having to write a
function to do it. :-( :-(
https://news.ycombinator.com/item?id=38926582
https://www.postofficehorizoninquiry.org.uk/evidence/fuj00080690-report-eposs-pinicl-task-force
See page 17 onwards of the PDF. :-(
Innocent people went to jail because of the system this code is
a part of, and because of the coverup around it, and it took
a TV drama to really get things moving. :-(
So, yes, I may make fun of your line numbers, but at least you most
certainly know what you are doing, unlike the above people.
The code is VB6.

But none of the problems are Basic specific. It is possible
to write the same bad code in C or Fortran or whatever.

So it just shows that there are some really really bad programmers out
there.

Arne

PS: Good compilers may have detected the unreachable code. But it
is still good vs bad compiler not good vs bad language.
k***@panix.com
2024-01-30 00:50:47 UTC
Permalink
Post by Arne Vajhøj
The code is VB6.
But none of the problems are Basic specific. It is possible
to write the same bad code in C or Fortran or whatever.
So it just shows that there are some really really bad programmers out
there.
I have worked with people who could write spaghetti Fortran in any
programming language available. Did you know that LISP has a goto?
It does.
Post by Arne Vajhøj
PS: Good compilers may have detected the unreachable code. But it
is still good vs bad compiler not good vs bad language.
The exciting part is when they tell you not to remove the unreachable code,
because the program crashes at runtime when you do that.
--scott
Lawrence D'Oliveiro
2024-01-30 00:55:00 UTC
Permalink
Post by k***@panix.com
Did you know that LISP has a goto?
Scheme doesn’t. It has continuations, which are a cool thing that can be
used to implement control structures, exceptions and coroutines, yet make
it quite difficult to express arbitrary gotos. Win-win, really.
Arne Vajhøj
2024-01-30 01:02:35 UTC
Permalink
Post by k***@panix.com
Post by Arne Vajhøj
The code is VB6.
But none of the problems are Basic specific. It is possible
to write the same bad code in C or Fortran or whatever.
So it just shows that there are some really really bad programmers out
there.
I have worked with people who could write spaghetti Fortran in any
programming language available.
"A real Fortran programmer can write Fortran in any language"

Every time this comes up I post this Fortran/Pascal code:

PROGRAM GOTOFUN(INPUT,OUTPUT);
LABEL L731,L113,L247,L588,L761,L922,L399,L601;
VAR LBL:INTEGER;
VAR I:INTEGER;
BEGIN
L731: GOTO L113;
LBL:=399;
L113: I:=0;
WRITELN(I);
L247: LBL:=601;
IF(I<0)THEN GOTO L588 ELSE IF(I=0)THEN GOTO L922 ELSE GOTO L399;
L588: I:=I+1;
WRITELN(I);
GOTO L399;
L761: CASE(LBL)OF 399: GOTO L399; 601: GOTO L601; END;
L922: I:=I+1;
WRITELN(I);
CASE(I)OF 1: GOTO L588; 2: GOTO L399; 3: GOTO L922; END;
L399: GOTO L761;
L601: END.

:-)

Arne
Dave Froble
2024-01-30 07:06:06 UTC
Permalink
Post by Arne Vajhøj
Post by k***@panix.com
Post by Arne Vajhøj
The code is VB6.
But none of the problems are Basic specific. It is possible
to write the same bad code in C or Fortran or whatever.
So it just shows that there are some really really bad programmers out
there.
I have worked with people who could write spaghetti Fortran in any
programming language available.
"A real Fortran programmer can write Fortran in any language"
PROGRAM GOTOFUN(INPUT,OUTPUT);
LABEL L731,L113,L247,L588,L761,L922,L399,L601;
VAR LBL:INTEGER;
VAR I:INTEGER;
BEGIN
L731: GOTO L113;
LBL:=399;
L113: I:=0;
WRITELN(I);
L247: LBL:=601;
IF(I<0)THEN GOTO L588 ELSE IF(I=0)THEN GOTO L922 ELSE GOTO L399;
L588: I:=I+1;
WRITELN(I);
GOTO L399;
L761: CASE(LBL)OF 399: GOTO L399; 601: GOTO L601; END;
L922: I:=I+1;
WRITELN(I);
CASE(I)OF 1: GOTO L588; 2: GOTO L399; 3: GOTO L922; END;
L399: GOTO L761;
L601: END.
:-)
Arne
I'm amused every time the GoTo bashing begins.

Not only is there nothing wrong when using a branch operation, when appropriate,
just look at the assembler listings after compilation. Branching is just about
all assembler does, as required.

Now, I won't defend what I and most consider improper use of the poor
misunderstood GoTo statement.
--
David Froble Tel: 724-529-0450
Dave Froble Enterprises, Inc. E-Mail: ***@tsoft-inc.com
DFE Ultralights, Inc.
170 Grimplin Road
Vanderbilt, PA 15486
Chris Townley
2024-01-30 14:40:34 UTC
Permalink
Post by Dave Froble
Post by Arne Vajhøj
Post by k***@panix.com
Post by Arne Vajhøj
The code is VB6.
But none of the problems are Basic specific. It is possible
to write the same bad code in C or Fortran or whatever.
So it just shows that there are some really really bad programmers out
there.
I have worked with people who could write spaghetti Fortran in any
programming language available.
"A real Fortran programmer can write Fortran in any language"
      PROGRAM GOTOFUN(INPUT,OUTPUT);
      LABEL L731,L113,L247,L588,L761,L922,L399,L601;
      VAR LBL:INTEGER;
      VAR I:INTEGER;
      BEGIN
L731: GOTO L113;
      LBL:=399;
L113: I:=0;
      WRITELN(I);
L247: LBL:=601;
      IF(I<0)THEN GOTO L588 ELSE IF(I=0)THEN GOTO L922 ELSE GOTO L399;
L588: I:=I+1;
      WRITELN(I);
      GOTO L399;
L761: CASE(LBL)OF 399: GOTO L399; 601: GOTO L601; END;
L922: I:=I+1;
      WRITELN(I);
      CASE(I)OF 1: GOTO L588; 2: GOTO L399; 3: GOTO L922; END;
L399: GOTO L761;
L601: END.
:-)
Arne
I'm amused every time the GoTo bashing begins.
Not only is there nothing wrong when using a branch operation, when
appropriate, just look at the assembler listings after compilation.
Branching is just about all assembler does, as required.
Now, I won't defend what I and most consider improper use of the poor
misunderstood GoTo statement.
But unless used very carefully, it can create horrible spaghetti like
code, and is also easy to screw up.

Using proper structured constructs is much better - easier to read as
well, hence better maintainability.
--
Chris
Dave Froble
2024-01-31 04:28:53 UTC
Permalink
Post by Dave Froble
Post by Arne Vajhøj
Post by k***@panix.com
Post by Arne Vajhøj
The code is VB6.
But none of the problems are Basic specific. It is possible
to write the same bad code in C or Fortran or whatever.
So it just shows that there are some really really bad programmers out
there.
I have worked with people who could write spaghetti Fortran in any
programming language available.
"A real Fortran programmer can write Fortran in any language"
PROGRAM GOTOFUN(INPUT,OUTPUT);
LABEL L731,L113,L247,L588,L761,L922,L399,L601;
VAR LBL:INTEGER;
VAR I:INTEGER;
BEGIN
L731: GOTO L113;
LBL:=399;
L113: I:=0;
WRITELN(I);
L247: LBL:=601;
IF(I<0)THEN GOTO L588 ELSE IF(I=0)THEN GOTO L922 ELSE GOTO L399;
L588: I:=I+1;
WRITELN(I);
GOTO L399;
L761: CASE(LBL)OF 399: GOTO L399; 601: GOTO L601; END;
L922: I:=I+1;
WRITELN(I);
CASE(I)OF 1: GOTO L588; 2: GOTO L399; 3: GOTO L922; END;
L399: GOTO L761;
L601: END.
:-)
Arne
I'm amused every time the GoTo bashing begins.
Not only is there nothing wrong when using a branch operation, when
appropriate, just look at the assembler listings after compilation. Branching
is just about all assembler does, as required.
Now, I won't defend what I and most consider improper use of the poor
misunderstood GoTo statement.
But unless used very carefully, it can create horrible spaghetti like code, and
is also easy to screw up.
Using proper structured constructs is much better - easier to read as well,
hence better maintainability.
Prey tell, what structured construct will perform cleanup and exit? I always
expected a return from routines and such.
--
David Froble Tel: 724-529-0450
Dave Froble Enterprises, Inc. E-Mail: ***@tsoft-inc.com
DFE Ultralights, Inc.
170 Grimplin Road
Vanderbilt, PA 15486
Chris Townley
2024-01-31 12:03:51 UTC
Permalink
Post by Dave Froble
Post by Arne Vajhøj
Post by k***@panix.com
Post by Arne Vajhøj
The code is VB6.
But none of the problems are Basic specific. It is possible
to write the same bad code in C or Fortran or whatever.
So it just shows that there are some really really bad programmers out
there.
I have worked with people who could write spaghetti Fortran in any
programming language available.
"A real Fortran programmer can write Fortran in any language"
      PROGRAM GOTOFUN(INPUT,OUTPUT);
      LABEL L731,L113,L247,L588,L761,L922,L399,L601;
      VAR LBL:INTEGER;
      VAR I:INTEGER;
      BEGIN
L731: GOTO L113;
      LBL:=399;
L113: I:=0;
      WRITELN(I);
L247: LBL:=601;
      IF(I<0)THEN GOTO L588 ELSE IF(I=0)THEN GOTO L922 ELSE GOTO L399;
L588: I:=I+1;
      WRITELN(I);
      GOTO L399;
L761: CASE(LBL)OF 399: GOTO L399; 601: GOTO L601; END;
L922: I:=I+1;
      WRITELN(I);
      CASE(I)OF 1: GOTO L588; 2: GOTO L399; 3: GOTO L922; END;
L399: GOTO L761;
L601: END.
:-)
Arne
I'm amused every time the GoTo bashing begins.
Not only is there nothing wrong when using a branch operation, when
appropriate, just look at the assembler listings after compilation.
Branching
is just about all assembler does, as required.
Now, I won't defend what I and most consider improper use of the poor
misunderstood GoTo statement.
But unless used very carefully, it can create horrible spaghetti like code, and
is also easy to screw up.
Using proper structured constructs is much better - easier to read as well,
hence better maintainability.
Prey tell, what structured construct will perform cleanup and exit?  I
always expected a return from routines and such.
It would depend on what is needing to be done
--
Chris
Dave Froble
2024-01-31 18:27:57 UTC
Permalink
Post by Chris Townley
Post by Dave Froble
Post by Dave Froble
Post by Arne Vajhøj
Post by k***@panix.com
Post by Arne Vajhøj
The code is VB6.
But none of the problems are Basic specific. It is possible
to write the same bad code in C or Fortran or whatever.
So it just shows that there are some really really bad programmers out
there.
I have worked with people who could write spaghetti Fortran in any
programming language available.
"A real Fortran programmer can write Fortran in any language"
PROGRAM GOTOFUN(INPUT,OUTPUT);
LABEL L731,L113,L247,L588,L761,L922,L399,L601;
VAR LBL:INTEGER;
VAR I:INTEGER;
BEGIN
L731: GOTO L113;
LBL:=399;
L113: I:=0;
WRITELN(I);
L247: LBL:=601;
IF(I<0)THEN GOTO L588 ELSE IF(I=0)THEN GOTO L922 ELSE GOTO L399;
L588: I:=I+1;
WRITELN(I);
GOTO L399;
L761: CASE(LBL)OF 399: GOTO L399; 601: GOTO L601; END;
L922: I:=I+1;
WRITELN(I);
CASE(I)OF 1: GOTO L588; 2: GOTO L399; 3: GOTO L922; END;
L399: GOTO L761;
L601: END.
:-)
Arne
I'm amused every time the GoTo bashing begins.
Not only is there nothing wrong when using a branch operation, when
appropriate, just look at the assembler listings after compilation. Branching
is just about all assembler does, as required.
Now, I won't defend what I and most consider improper use of the poor
misunderstood GoTo statement.
But unless used very carefully, it can create horrible spaghetti like code, and
is also easy to screw up.
Using proper structured constructs is much better - easier to read as well,
hence better maintainability.
Prey tell, what structured construct will perform cleanup and exit? I always
expected a return from routines and such.
It would depend on what is needing to be done
Final cleanup, if required, and exit the program.

Knew a guy that would us a gosub to go to the END statement. Drove me nuts.
--
David Froble Tel: 724-529-0450
Dave Froble Enterprises, Inc. E-Mail: ***@tsoft-inc.com
DFE Ultralights, Inc.
170 Grimplin Road
Vanderbilt, PA 15486
Chris Townley
2024-02-01 00:15:52 UTC
Permalink
Post by Dave Froble
Post by Chris Townley
Post by Dave Froble
Post by Dave Froble
Post by Arne Vajhøj
Post by k***@panix.com
Post by Arne Vajhøj
The code is VB6.
But none of the problems are Basic specific. It is possible
to write the same bad code in C or Fortran or whatever.
So it just shows that there are some really really bad
programmers out
there.
I have worked with people who could write spaghetti Fortran in any
programming language available.
"A real Fortran programmer can write Fortran in any language"
      PROGRAM GOTOFUN(INPUT,OUTPUT);
      LABEL L731,L113,L247,L588,L761,L922,L399,L601;
      VAR LBL:INTEGER;
      VAR I:INTEGER;
      BEGIN
L731: GOTO L113;
      LBL:=399;
L113: I:=0;
      WRITELN(I);
L247: LBL:=601;
      IF(I<0)THEN GOTO L588 ELSE IF(I=0)THEN GOTO L922 ELSE GOTO L399;
L588: I:=I+1;
      WRITELN(I);
      GOTO L399;
L761: CASE(LBL)OF 399: GOTO L399; 601: GOTO L601; END;
L922: I:=I+1;
      WRITELN(I);
      CASE(I)OF 1: GOTO L588; 2: GOTO L399; 3: GOTO L922; END;
L399: GOTO L761;
L601: END.
:-)
Arne
I'm amused every time the GoTo bashing begins.
Not only is there nothing wrong when using a branch operation, when
appropriate, just look at the assembler listings after
compilation.  Branching
is just about all assembler does, as required.
Now, I won't defend what I and most consider improper use of the poor
misunderstood GoTo statement.
But unless used very carefully, it can create horrible spaghetti like code, and
is also easy to screw up.
Using proper structured constructs is much better - easier to read as well,
hence better maintainability.
Prey tell, what structured construct will perform cleanup and exit?
I always
expected a return from routines and such.
It would depend on what is needing to be done
Final cleanup, if required, and exit the program.
Knew a guy that would us a gosub to go to the END statement.  Drove me
nuts.
We always used global error handling, as well as local when error...

At least with DEC Basic, it always handled garbage collection
--
Chris
Lawrence D'Oliveiro
2024-02-18 21:16:54 UTC
Permalink
Post by Dave Froble
Final cleanup, if required, and exit the program.
If the program is exiting, a lot of the leftover cleanup (e.g. memory
deallocation) becomes unnecessary.
Post by Dave Froble
Knew a guy that would us a gosub to go to the END statement. Drove me nuts.
Did it have a comment next to it saying “I’ll be back!”?
Michael S
2024-01-31 13:52:30 UTC
Permalink
On Tue, 30 Jan 2024 23:28:53 -0500
Post by Dave Froble
Prey tell, what structured construct will perform cleanup and exit?
I always expected a return from routines and such.
One option is named construct and named break.
Example below is from Go (golang) tutorial. Ada has something very
similar.

Loop:
for n := 0; n < len(src); n += size {
switch {
case src[n] < sizeOne:
if validateOnly {
break
}
size = 1
update(src[n])

case src[n] < sizeTwo:
if n+1 >= len(src) {
err = errShortInput
break Loop
}
if validateOnly {
break
}
size = 2
update(src[n] + src[n+1]<<shift)
}
}


Another option is defer clause.
From the same tutorial:

// Contents returns the file's contents as a string.
func Contents(filename string) (string, error) {
f, err := os.Open(filename)
if err != nil {
return "", err
}
defer f.Close() // f.Close will run when we're finished.

var result []byte
buf := make([]byte, 100)
for {
n, err := f.Read(buf[0:])
result = append(result, buf[0:n]...) // append is discussed
later. if err != nil {
if err == io.EOF {
break
}
return "", err // f will be closed if we return here.
}
}
return string(result), nil // f will be closed if we return here.
}

The third option, the one I like least (an understatement) is use of
exceptions. Despite my personal preferences, it's quite popular.
Scott Dorsey
2024-01-31 16:17:15 UTC
Permalink
Post by Michael S
The third option, the one I like least (an understatement) is use of
exceptions. Despite my personal preferences, it's quite popular.
Exceptions can be very elegant or very inelegant... and it is entirely
possible to have an exception that doesn't clean anything up at all and
just exits and lets the operating system deal with the memory. On many
systems this is a great idea because being able to exit quickly on a failure
is more important than people give it credit for. On some other systems
that have memory management issues it can lead to leakage.
--scott
--
"C'est un Nagra. C'est suisse, et tres, tres precis."
Arne Vajhøj
2024-01-31 18:29:30 UTC
Permalink
Post by Scott Dorsey
Post by Michael S
The third option, the one I like least (an understatement) is use of
exceptions. Despite my personal preferences, it's quite popular.
Exceptions can be very elegant or very inelegant... and it is entirely
possible to have an exception that doesn't clean anything up at all and
just exits and lets the operating system deal with the memory. On many
systems this is a great idea because being able to exit quickly on a failure
is more important than people give it credit for. On some other systems
that have memory management issues it can lead to leakage.
It is probably a bit easier to implement exceptions in languages
with garbage collection and a lot easier for developers to avoid
memory leak bugs.

$ type mem.cpp
#include <iostream>
#include <string>

using namespace std;

class X
{
private:
string id;
public:
X(string id) { this->id = id; cout << "Allocate " << id << endl; }
virtual ~X() { cout << "Deallocate " << id << endl; }
};

void f2()
{
throw "Houston we have a problem";
}

void f1()
{
X o2("o2");
X *o3 = new X("o3");
f2();
delete o3;
}

int main()
{
try
{
X o1("o1");
f1();
}
catch(char *ex)
{
cout << ex << endl;
}
return 0;
}

$ cxx mem.cpp
$ cxxlink mem
link mem
$ run mem
Allocate o1
Allocate o2
Allocate o3
Deallocate o2
Deallocate o1
Houston we have a problem
$

We see that o2 did get deallocated, but o3 did not get deallocated.

Arne
Dan Cross
2024-01-31 20:41:32 UTC
Permalink
Post by Arne Vajhøj
Post by Scott Dorsey
Post by Michael S
The third option, the one I like least (an understatement) is use of
exceptions. Despite my personal preferences, it's quite popular.
Exceptions can be very elegant or very inelegant... and it is entirely
possible to have an exception that doesn't clean anything up at all and
just exits and lets the operating system deal with the memory. On many
systems this is a great idea because being able to exit quickly on a failure
is more important than people give it credit for. On some other systems
that have memory management issues it can lead to leakage.
It is probably a bit easier to implement exceptions in languages
with garbage collection and a lot easier for developers to avoid
memory leak bugs.
$ type mem.cpp
#include <iostream>
#include <string>
using namespace std;
class X
{
string id;
X(string id) { this->id = id; cout << "Allocate " << id << endl; }
virtual ~X() { cout << "Deallocate " << id << endl; }
};
void f2()
{
throw "Houston we have a problem";
}
void f1()
{
X o2("o2");
X *o3 = new X("o3");
f2();
delete o3;
}
int main()
{
try
{
X o1("o1");
f1();
}
catch(char *ex)
{
cout << ex << endl;
}
return 0;
}
$ cxx mem.cpp
$ cxxlink mem
link mem
$ run mem
Allocate o1
Allocate o2
Allocate o3
Deallocate o2
Deallocate o1
Houston we have a problem
$
We see that o2 did get deallocated, but o3 did not get deallocated.
This is well-known in older C++ code; since C++11 one should be
using `std::unique_ptr<T>` to avoid this sort of issue. Code
using an older dialect could look at something like the
venerable ScopeGuard as a defensive technique to guard against
leaks.
https://www.drdobbs.com/article/print?articleId=184403758&siteSectionName=cpp

- Dan C.
Scott Dorsey
2024-02-02 01:44:41 UTC
Permalink
Post by Arne Vajhøj
Post by Scott Dorsey
Post by Michael S
The third option, the one I like least (an understatement) is use of
exceptions. Despite my personal preferences, it's quite popular.
Exceptions can be very elegant or very inelegant... and it is entirely
possible to have an exception that doesn't clean anything up at all and
just exits and lets the operating system deal with the memory. On many
systems this is a great idea because being able to exit quickly on a failure
is more important than people give it credit for. On some other systems
that have memory management issues it can lead to leakage.
It is probably a bit easier to implement exceptions in languages
with garbage collection and a lot easier for developers to avoid
memory leak bugs.
True, but "dispose of all memory belonging to this process" should not be
a big deal on a demand-paged machine. There are some architectures where
it can be, though.
--scott
--
"C'est un Nagra. C'est suisse, et tres, tres precis."
Arne Vajhøj
2024-02-02 02:29:57 UTC
Permalink
Post by Scott Dorsey
Post by Arne Vajhøj
Post by Scott Dorsey
Post by Michael S
The third option, the one I like least (an understatement) is use of
exceptions. Despite my personal preferences, it's quite popular.
Exceptions can be very elegant or very inelegant... and it is entirely
possible to have an exception that doesn't clean anything up at all and
just exits and lets the operating system deal with the memory. On many
systems this is a great idea because being able to exit quickly on a failure
is more important than people give it credit for. On some other systems
that have memory management issues it can lead to leakage.
It is probably a bit easier to implement exceptions in languages
with garbage collection and a lot easier for developers to avoid
memory leak bugs.
True, but "dispose of all memory belonging to this process" should not be
a big deal on a demand-paged machine. There are some architectures where
it can be, though.
The issue is not if the process goes away but if the process
continue after execution flow has dropped back a number of levels
on the call stack.

The C++ code I posted did exit, but main could have called
f1 again after catching the exception. Maybe doing it
a billion times leaking one object for every call.

Arne
Scott Dorsey
2024-02-03 01:23:27 UTC
Permalink
Post by Arne Vajhøj
Post by Scott Dorsey
Post by Arne Vajhøj
Post by Scott Dorsey
Post by Michael S
The third option, the one I like least (an understatement) is use of
exceptions. Despite my personal preferences, it's quite popular.
Exceptions can be very elegant or very inelegant... and it is entirely
possible to have an exception that doesn't clean anything up at all and
just exits and lets the operating system deal with the memory. On many
systems this is a great idea because being able to exit quickly on a failure
is more important than people give it credit for. On some other systems
that have memory management issues it can lead to leakage.
It is probably a bit easier to implement exceptions in languages
with garbage collection and a lot easier for developers to avoid
memory leak bugs.
True, but "dispose of all memory belonging to this process" should not be
a big deal on a demand-paged machine. There are some architectures where
it can be, though.
The issue is not if the process goes away but if the process
continue after execution flow has dropped back a number of levels
on the call stack.
Yes, but that's a different problem. I'm talking about an "abort and get
the hell out of there" routine.
--scott
--
"C'est un Nagra. C'est suisse, et tres, tres precis."
Lawrence D'Oliveiro
2024-01-31 21:28:01 UTC
Permalink
Post by Michael S
One option is named construct and named break.
I have never written a goto in C code (not production code, anyway). These
days, you need to do so much dynamic allocation, there is nearly always
some need for cleanup when exiting an inner block anyway, so you can’t
just jump directly somewhere else first. The overall pattern looks like
this:

MyPtr obj = NULL;
do /*once*/
{
... possible other stuff ...
«allocate memory for obj»;
if («error occurred»)
break;
... possible other stuff using obj ...
}
while (false);
free(obj);

You can confirm, just by inspection, that there is no path out of the
block that does not pass through the free() call precisely once.
Arne Vajhøj
2024-01-31 22:08:44 UTC
Permalink
Post by Lawrence D'Oliveiro
I have never written a goto in C code (not production code, anyway). These
days, you need to do so much dynamic allocation, there is nearly always
some need for cleanup when exiting an inner block anyway, so you can’t
just jump directly somewhere else first. The overall pattern looks like
MyPtr obj = NULL;
do /*once*/
{
... possible other stuff ...
«allocate memory for obj»;
if («error occurred»)
break;
... possible other stuff using obj ...
}
while (false);
free(obj);
You can confirm, just by inspection, that there is no path out of the
block that does not pass through the free() call precisely once.
And the difference compared to:

MyPtr obj = NULL;
... possible other stuff ...
«allocate memory for obj»;
if («error occurred»)
goto lbl_freeobj;
... possible other stuff using obj ...
lbl_freeobj:
free(obj);

are?

Arne
Dave Froble
2024-01-31 23:04:52 UTC
Permalink
Post by Lawrence D'Oliveiro
Post by Lawrence D'Oliveiro
I have never written a goto in C code (not production code, anyway). These
days, you need to do so much dynamic allocation, there is nearly always
some need for cleanup when exiting an inner block anyway, so you can’t
just jump directly somewhere else first. The overall pattern looks like
MyPtr obj = NULL;
do /*once*/
{
... possible other stuff ...
«allocate memory for obj»;
if («error occurred»)
break;
... possible other stuff using obj ...
}
while (false);
free(obj);
You can confirm, just by inspection, that there is no path out of the
block that does not pass through the free() call precisely once.
MyPtr obj = NULL;
... possible other stuff ...
«allocate memory for obj»;
if («error occurred»)
goto lbl_freeobj;
... possible other stuff using obj ...
free(obj);
are?
Arne
I've seen code that did all kinds of confusing things, just avoid a GoTo branch.
My question is, why? If the need is a simple and rather easy to understand
branch, why get complex, just to be "political correct", which ia also a rather
stupid concept.
--
David Froble Tel: 724-529-0450
Dave Froble Enterprises, Inc. E-Mail: ***@tsoft-inc.com
DFE Ultralights, Inc.
170 Grimplin Road
Vanderbilt, PA 15486
Dan Cross
2024-02-01 01:26:12 UTC
Permalink
Post by Dave Froble
I've seen code that did all kinds of confusing things, just avoid a GoTo branch.
My question is, why? If the need is a simple and rather easy to understand
branch, why get complex,
`goto` by itself is a sharp tool; sometimes incredibly useful,
but dangerous if misused. Our industry is littered with example
after example of `goto` misused. For instance,
https://dwheeler.com/essays/apple-goto-fail.html

Because of the potential and history of misuse, it's a laudable
goal to reduce use of `goto`, and indeed, over the years we've
seen generations of languages where the primary use cases have
been analyzed and the most useful lifted into new constructs
that become first-class parts of their respective languages;
`break` and `continue` for loops, exceptions, and so on.

Moreover, this is useful in the sense that programming languages
also serve a communicative purpose. How many of us would change
a `for` loop to if's and gotos given the choice? I wager few
would; the former communicates intent far more clearly than the
latter. For that matter, if we could iterate over a collection,
that's even better again.

That said, `goto` obviously _does_ have a place when used
judiciously. As Ken Thompson once said, "if you want to go
somewhere, goto is the best way to get there." Like all goals,
the desire to reduce `goto` prevelence is mostly aspirational.
Certainly, we're well past the context of Djikstra's "GO TO
STATEMENT CONSIDERED HARMFUL" CACM letter.

- Dan C.
Dave Froble
2024-02-01 03:57:47 UTC
Permalink
Post by Dan Cross
Post by Dave Froble
I've seen code that did all kinds of confusing things, just avoid a GoTo branch.
My question is, why? If the need is a simple and rather easy to understand
branch, why get complex,
`goto` by itself is a sharp tool; sometimes incredibly useful,
but dangerous if misused. Our industry is littered with example
after example of `goto` misused. For instance,
https://dwheeler.com/essays/apple-goto-fail.html
Cars are dangerous, should we go back to horses?
Horses are dangerous, should we go back to walking?
Walking is dangerous ...

Flying is dangerous ...
Boats are dangerous ...

Crossing the street is dangerous. But we're taught to look before stepping in
front of the bus.

GoTo can be dangerous ...
Learn good programming habits ...
Post by Dan Cross
That said, `goto` obviously _does_ have a place when used
judiciously.
Yes, that ...
--
David Froble Tel: 724-529-0450
Dave Froble Enterprises, Inc. E-Mail: ***@tsoft-inc.com
DFE Ultralights, Inc.
170 Grimplin Road
Vanderbilt, PA 15486
Single Stage to Orbit
2024-02-01 08:43:12 UTC
Permalink
Post by Dave Froble
GoTo can be dangerous ...
Learn good programming habits ...
Linux uses goto in the kernel a lot. Should I throw it in the bin?
--
Tactical Nuclear Kittens
Dan Cross
2024-02-01 13:04:13 UTC
Permalink
Post by Single Stage to Orbit
Post by Dave Froble
GoTo can be dangerous ...
Learn good programming habits ...
Linux uses goto in the kernel a lot. Should I throw it in the bin?
I see the point has gone over multiple people's heads, which
probably means I did a poor job explaining. Like I said, `goto`
*can* be useful. Does that mean we should use it in lieu of
structued constructs like loops, when available? No.

It's silly to deny that `goto` has been abused, leading to lots
of very poor code. This is and was well-known. Rising to the
defense of `goto` without acknowledging its faults is similarly
silly.

- Dan C.
Dave Froble
2024-02-02 02:43:42 UTC
Permalink
Post by Single Stage to Orbit
Post by Dave Froble
GoTo can be dangerous ...
Learn good programming habits ...
Linux uses goto in the kernel a lot. Should I throw it in the bin?
Pitch it because it's Linux, not because of the goto

:-)
--
David Froble Tel: 724-529-0450
Dave Froble Enterprises, Inc. E-Mail: ***@tsoft-inc.com
DFE Ultralights, Inc.
170 Grimplin Road
Vanderbilt, PA 15486
Single Stage to Orbit
2024-02-02 10:36:47 UTC
Permalink
Post by Dave Froble
Post by Single Stage to Orbit
Post by Dave Froble
GoTo can be dangerous ...
Learn good programming habits ...
Linux uses goto in the kernel a lot. Should I throw it in the bin?
Pitch it because it's Linux, not because of the goto
Oo them's flammable words. :-D
--
Tactical Nuclear Kittens
Dan Cross
2024-02-01 13:00:47 UTC
Permalink
Post by Dave Froble
Post by Dan Cross
Post by Dave Froble
I've seen code that did all kinds of confusing things, just avoid a GoTo branch.
My question is, why? If the need is a simple and rather easy to understand
branch, why get complex,
`goto` by itself is a sharp tool; sometimes incredibly useful,
but dangerous if misused. Our industry is littered with example
after example of `goto` misused. For instance,
https://dwheeler.com/essays/apple-goto-fail.html
Cars are dangerous, should we go back to horses?
I think the analogy is more like, "cars are dangerous, so should
we get rid of seatbelts?" Or, "Takata made dangerous air bags,
so what's the point of having them at all?"
Post by Dave Froble
Horses are dangerous, should we go back to walking?
Walking is dangerous ...
Flying is dangerous ...
Boats are dangerous ...
Crossing the street is dangerous. But we're taught to look before stepping in
front of the bus.
GoTo can be dangerous ...
Learn good programming habits ...
I wonder if you read the rest of my post which tried, perhaps
imperfectly, to say more or less the same thing.
Post by Dave Froble
Post by Dan Cross
That said, `goto` obviously _does_ have a place when used
judiciously.
Yes, that ...
Just so.

- Dan C.
Simon Clubley
2024-02-01 13:24:46 UTC
Permalink
Post by Dave Froble
Post by Dan Cross
Post by Dave Froble
I've seen code that did all kinds of confusing things, just avoid a GoTo branch.
My question is, why? If the need is a simple and rather easy to understand
branch, why get complex,
`goto` by itself is a sharp tool; sometimes incredibly useful,
but dangerous if misused. Our industry is littered with example
after example of `goto` misused. For instance,
https://dwheeler.com/essays/apple-goto-fail.html
Cars are dangerous, should we go back to horses?
No, but we introduced safety measures based on experience.
Post by Dave Froble
Horses are dangerous, should we go back to walking?
No, but we introduced safety measures based on experience.
Post by Dave Froble
Walking is dangerous ...
We introduced safety measures based on experience (depending on
the type of walking you are doing).
Post by Dave Froble
Flying is dangerous ...
We introduced safety measures based on experience.
Post by Dave Froble
Boats are dangerous ...
We introduced safety measures based on experience.
Post by Dave Froble
GoTo can be dangerous ...
Learn good programming habits ...
We introduced safer alternatives based on experience.

Simon.
--
Simon Clubley, ***@remove_me.eisner.decus.org-Earth.UFP
Walking destinations on a map are further away than they appear.
Lawrence D'Oliveiro
2024-02-18 21:19:20 UTC
Permalink
Post by Dave Froble
Cars are dangerous, should we go back to horses?
Fun fact: according to drug expert David Nutt, horse-riding is about as
dangerous as taking Ecstasy.

Do horses have seatbelts and crumple zones yet?

Lawrence D'Oliveiro
2024-01-31 23:21:34 UTC
Permalink
Post by Lawrence D'Oliveiro
Post by Lawrence D'Oliveiro
I have never written a goto in C code (not production code, anyway). These
days, you need to do so much dynamic allocation, there is nearly always
some need for cleanup when exiting an inner block anyway, so you can’t
just jump directly somewhere else first. The overall pattern looks like
MyPtr obj = NULL;
do /*once*/
{
... possible other stuff ...
«allocate memory for obj»;
if («error occurred»)
break;
... possible other stuff using obj ...
}
while (false);
free(obj);
You can confirm, just by inspection, that there is no path out of the
block that does not pass through the free() call precisely once.
MyPtr obj = NULL;
... possible other stuff ...
«allocate memory for obj»;
if («error occurred»)
goto lbl_freeobj;
... possible other stuff using obj ...
free(obj);
are?
Nesting. Try to scale up to something like

static PyObject * discipline_makedict
(
PyObject * self,
PyObject * args
)
{
PyObject * result = NULL;
PyObject * tempresult = NULL;
br_PyObject * items;
const br_char * msg = NULL;
do /*once*/
{
const bool parsed_ok = PyArg_ParseTuple(args, "Os", &items, &msg);
if (not parsed_ok)
break;
fprintf(stdout, "makedict says: “%s”\n", msg);
if (not PyTuple_Check(items))
{
PyErr_SetString(PyExc_TypeError, "expecting a tuple");
break;
} /*if*/
const ssize_t nr_items = PyTuple_Size(items);
if (PyErr_Occurred())
break;
tempresult = PyDict_New();
if (tempresult == NULL)
break;
for (ssize_t i = 0;;)
{
if (i == nr_items)
break;
br_PyObject * const item = PyTuple_GetItem(items, i);
if (item == NULL)
break;
if (not PyTuple_Check(item) or PyTuple_Size(item) != 2)
{
PyErr_SetString(PyExc_TypeError, "expecting a 2-tuple");
break;
} /*if*/
br_PyObject * const first = PyTuple_GetItem(item, 0);
if (first == NULL)
break;
br_PyObject * const second = PyTuple_GetItem(item, 1);
if (second == NULL)
break;
if (first == (PyObject *)&ExceptMe_type or second == (PyObject *)&ExceptMe_type)
{
PyErr_SetString(PyExc_ValueError, "ExceptMe object found");
break;
} /*if*/
if (PyDict_SetItem(tempresult, first, second) < 0)
break;
++i;
} /*for*/
if (PyErr_Occurred())
break;
/* all done */
result = tempresult;
tempresult = NULL; /* so I don’t dispose of it yet */
}
while (false);
Py_XDECREF(tempresult);
return
result;
} /*discipline_makedict*/

More details here
<https://gitlab.com/ldo/a_structured_discipline_of_programming/>.
Arne Vajhøj
2024-02-01 00:29:14 UTC
Permalink
Post by Lawrence D'Oliveiro
Post by Lawrence D'Oliveiro
Post by Lawrence D'Oliveiro
I have never written a goto in C code (not production code, anyway). These
days, you need to do so much dynamic allocation, there is nearly always
some need for cleanup when exiting an inner block anyway, so you can’t
just jump directly somewhere else first. The overall pattern looks like
MyPtr obj = NULL;
do /*once*/
{
... possible other stuff ...
«allocate memory for obj»;
if («error occurred»)
break;
... possible other stuff using obj ...
}
while (false);
free(obj);
You can confirm, just by inspection, that there is no path out of the
block that does not pass through the free() call precisely once.
MyPtr obj = NULL;
... possible other stuff ...
«allocate memory for obj»;
if («error occurred»)
goto lbl_freeobj;
... possible other stuff using obj ...
free(obj);
are?
Nesting.
Goto work fine with nested loops. In fact it is one of the cases
where it really makes sense.
Post by Lawrence D'Oliveiro
Try to scale up to something like
static PyObject * discipline_makedict
(
PyObject * self,
PyObject * args
)
{
PyObject * result = NULL;
PyObject * tempresult = NULL;
br_PyObject * items;
const br_char * msg = NULL;
do /*once*/
{
const bool parsed_ok = PyArg_ParseTuple(args, "Os", &items, &msg);
if (not parsed_ok)
break;
fprintf(stdout, "makedict says: “%s”\n", msg);
if (not PyTuple_Check(items))
{
PyErr_SetString(PyExc_TypeError, "expecting a tuple");
break;
} /*if*/
const ssize_t nr_items = PyTuple_Size(items);
if (PyErr_Occurred())
break;
tempresult = PyDict_New();
if (tempresult == NULL)
break;
for (ssize_t i = 0;;)
{
if (i == nr_items)
break;
br_PyObject * const item = PyTuple_GetItem(items, i);
if (item == NULL)
break;
if (not PyTuple_Check(item) or PyTuple_Size(item) != 2)
{
PyErr_SetString(PyExc_TypeError, "expecting a 2-tuple");
break;
} /*if*/
br_PyObject * const first = PyTuple_GetItem(item, 0);
if (first == NULL)
break;
br_PyObject * const second = PyTuple_GetItem(item, 1);
if (second == NULL)
break;
if (first == (PyObject *)&ExceptMe_type or second == (PyObject *)&ExceptMe_type)
{
PyErr_SetString(PyExc_ValueError, "ExceptMe object found");
break;
} /*if*/
if (PyDict_SetItem(tempresult, first, second) < 0)
break;
++i;
} /*for*/
if (PyErr_Occurred())
break;
/* all done */
result = tempresult;
tempresult = NULL; /* so I don’t dispose of it yet */
}
while (false);
Py_XDECREF(tempresult);
return
result;
} /*discipline_makedict*/
That code would look a lot cleaner if the do while(false) loop got
removed and the relevant breaks got replaced by goto's.

A well named goto label is much more informative than a plain break.
Post by Lawrence D'Oliveiro
More details here
<https://gitlab.com/ldo/a_structured_discipline_of_programming/>.
Truly bad design.

All the code examples would look better with the do while(false) loops
removed and appropriate goto's.

Arne
Dan Cross
2024-02-01 01:59:13 UTC
Permalink
Post by Arne Vajhøj
[snip]
Nesting.
Goto work fine with nested loops. In fact it is one of the cases
where it really makes sense.
I think the troll was referring to nested control structures,
with nested resource handling.
Post by Arne Vajhøj
Try to scale up to something like
static PyObject * discipline_makedict
(
PyObject * self,
PyObject * args
)
{
PyObject * result = NULL;
PyObject * tempresult = NULL;
br_PyObject * items;
const br_char * msg = NULL;
do /*once*/
{
const bool parsed_ok = PyArg_ParseTuple(args, "Os", &items, &msg);
if (not parsed_ok)
break;
fprintf(stdout, "makedict says: “%s”\n", msg);
if (not PyTuple_Check(items))
{
PyErr_SetString(PyExc_TypeError, "expecting a tuple");
break;
} /*if*/
const ssize_t nr_items = PyTuple_Size(items);
if (PyErr_Occurred())
break;
tempresult = PyDict_New();
if (tempresult == NULL)
break;
for (ssize_t i = 0;;)
{
if (i == nr_items)
break;
br_PyObject * const item = PyTuple_GetItem(items, i);
if (item == NULL)
break;
if (not PyTuple_Check(item) or PyTuple_Size(item) != 2)
{
PyErr_SetString(PyExc_TypeError, "expecting a 2-tuple");
break;
} /*if*/
br_PyObject * const first = PyTuple_GetItem(item, 0);
if (first == NULL)
break;
br_PyObject * const second = PyTuple_GetItem(item, 1);
if (second == NULL)
break;
if (first == (PyObject *)&ExceptMe_type or second == (PyObject *)&ExceptMe_type)
{
PyErr_SetString(PyExc_ValueError, "ExceptMe object found");
break;
} /*if*/
if (PyDict_SetItem(tempresult, first, second) < 0)
break;
++i;
} /*for*/
if (PyErr_Occurred())
break;
/* all done */
result = tempresult;
tempresult = NULL; /* so I don’t dispose of it yet */
}
while (false);
Py_XDECREF(tempresult);
return
result;
} /*discipline_makedict*/
That code would look a lot cleaner if the do while(false) loop got
removed and the relevant breaks got replaced by goto's.
I almost agree. That could is borderline unreadable, but if one
detangles it from the weird web of style its obfuscated by, one
realizes it can be written in a far more straight-forward manner
without either `goto` or the weird do/while style. Near as I
can tell, the following rough cut is equivalent to the original:

static PyObject *
discipline_makedict(PyObject *self, PyObject *args)
{
br_PyObject *items;
const br_char *msg = NULL;

const bool parsed_ok = PyArg_ParseTuple(args, "Os", &items, &msg);
if (!parsed_ok)
return NULL;

printf("makedict says: \xe2\x80\x9c%s\xe2\x80\x9d\n", msg);
if (!PyTuple_Check(items)) {
PyErr_SetString(PyExc_TypeError, "expecting a tuple");
return NULL;
}
const ssize_t nitems = PyTuple_Size(items);
if (PyErr_Occurred())
return NULL;

PyObject *result = PyDict_New();
if (result == NULL)
return NULL;

for (ssize_t i = 0; i < nitems; ++i) {
br_PyObject *const item = PyTuple_GetItem(items, i);
if (item == NULL)
break;
if (!PyTuple_Check(item) || PyTuple_Size(item) != 2) {
PyErr_SetString(PyExc_TypeError, "expecting a 2-tuple");
break;
}
br_PyObject *const first = PyTuple_GetItem(item, 0);
if (first == NULL)
break;
br_PyObject *const second = PyTuple_GetItem(item, 1);
if (second == NULL)
break;
if (first == (PyObject *)&ExceptMe_type || second == (PyObject *)&ExceptMe_type) {
PyErr_SetString(PyExc_ValueError, "ExceptMe object found");
break;
}
if (PyDict_SetItem(result, first, second) < 0)
break;
}

if (PyErr_Occurred()) {
Py_XDECREF(result);
return NULL;
}

return result;
}

I would argue this is more idiomatic, shorter, simpler, easier
to both read and to reason about, and uses fewer variables.

I couldn't really figure out why the `printf` was in there, so I
left it in; it looks like debugging code though. I didn't test
it, however, since I don't really care.
Post by Arne Vajhøj
A well named goto label is much more informative than a plain break.
Agreed. In this case, the breaks are sufficiently contained
once the rest of the cruft is cut away that I don't think a goto
is any better.
Post by Arne Vajhøj
More details here
<https://gitlab.com/ldo/a_structured_discipline_of_programming/>.
Truly bad design.
All the code examples would look better with the do while(false) loops
removed and appropriate goto's.
Agreed. That code is straight garbage, and should not make it
past any serious review.

- Dan C.
Simon Clubley
2024-02-01 13:21:10 UTC
Permalink
Post by Dan Cross
I would argue this is more idiomatic, shorter, simpler, easier
to both read and to reason about, and uses fewer variables.
I agree and this is the general style I use, but with one difference.
In my code, I always, always, use braces in an if() statement, even
if the conditional code is only a single statement. For example:

const bool parsed_ok = PyArg_ParseTuple(args, "Os", &items, &msg);
if (!parsed_ok)
{
return NULL;
}

I think that makes it more clear and removes any possibility of future
code changes accidentally not adding the braces at that time.

[And yes, about the above indentation, Simon _is_ indeed a Whitesmiths
person. :-)]

Simon.
--
Simon Clubley, ***@remove_me.eisner.decus.org-Earth.UFP
Walking destinations on a map are further away than they appear.
Dan Cross
2024-02-01 13:41:03 UTC
Permalink
Post by Simon Clubley
Post by Dan Cross
I would argue this is more idiomatic, shorter, simpler, easier
to both read and to reason about, and uses fewer variables.
I agree and this is the general style I use, but with one difference.
In my code, I always, always, use braces in an if() statement, even
const bool parsed_ok = PyArg_ParseTuple(args, "Os", &items, &msg);
if (!parsed_ok)
{
return NULL;
}
I think that makes it more clear and removes any possibility of future
code changes accidentally not adding the braces at that time.
That's fine. Indeed, many modern languages mandate braces in
around the bodies of conditionals and loops as part of the base
syntax of the language (Go and Rust both do). I didn't bother
because I only made the minimal changes to that crank's code.
Post by Simon Clubley
[And yes, about the above indentation, Simon _is_ indeed a Whitesmiths
person. :-)]
From, Henry Spencer's, "The Ten Commandments for C Programmers":

|8. Thou shalt make thy program's purpose and structure clear to
|thy fellow man by using the One True Brace Style, even if thou
|likest it not, for thy creativity is better used in solving
|problems than in creating beautiful new impediments to
|understanding.

It is somewhat odd to me how contentious this is after so many
years, but I kind of get how attached one can be to a particular
code style. When I worked at Google, I thought the mandated
style for C++ code was hideously ugly; after a few weeks, I
stopped noticing. When `clang-format` came along, it was great
because it essentially eliminated all of the stupid style things
from reviews. Go and Rust (and other modern languages)
effectively ended this as an issue by shipping with code
formatters and making people use them.

The bottom line for me, for C/C++ code, is that I don't care
what style one uses, as long as one is consistent; it is
shocking the extent to which divergent styles within a code base
can increase cognitive load.

- Dan C.
Arne Vajhøj
2024-02-01 23:40:00 UTC
Permalink
Post by Simon Clubley
Post by Dan Cross
I would argue this is more idiomatic, shorter, simpler, easier
to both read and to reason about, and uses fewer variables.
I agree and this is the general style I use, but with one difference.
In my code, I always, always, use braces in an if() statement, even
const bool parsed_ok = PyArg_ParseTuple(args, "Os", &items, &msg);
if (!parsed_ok)
{
return NULL;
}
I think that makes it more clear and removes any possibility of future
code changes accidentally not adding the braces at that time.
That is a common coding convention.

Including the original SUN Java coding convention from 1999.

Arne
Lawrence D'Oliveiro
2024-02-01 23:59:49 UTC
Permalink
Post by Arne Vajhøj
Post by Lawrence D'Oliveiro
const bool parsed_ok = PyArg_ParseTuple(args, "Os", &items, &msg);
if (!parsed_ok)
{
return NULL;
}
That is a common coding convention.
How do you handle nesting? Remember this part?

if (PyDict_SetItem(tempresult, first, second) < 0)
break;

If you did a return instead at that point, it would leak memory.

Note also the handover of ownership after all successful allocations, at
the end of the block:

} /*for*/
if (PyErr_Occurred())
break;
/* all done */
result = tempresult;
tempresult = NULL; /* so I don’t dispose of it yet */

This way, the cleanup at the end does not need to distinguish between
success and failure returns:

Py_XDECREF(tempresult);
return
result;
James Pemberton
2024-02-02 00:46:26 UTC
Permalink
Buy all your psychedelic products with me including clone cards
All products are available for deliveries and drop offs
Fast shipping and delivery of packages to all locations worldwide
Let me know with your orders
Text me on telegram @Only1cross
You can also join my channel for more products and reviews,link below

https://t.me/trippycross2
https://t.me/trippycross2
https://t.me/trippycross2
https://t.me/trippycross2

You can let me know anytime with your orders
Prices are also slightly negotiable depending on the quantity needed
Lawrence D'Oliveiro
2024-02-01 02:49:13 UTC
Permalink
Post by Arne Vajhøj
That code would look a lot cleaner if the do while(false) loop got
removed and the relevant breaks got replaced by goto's.
Show us how you would do it. I can take you through my code step by step,
block by block, if that will help.
Dan Cross
2024-02-01 13:18:31 UTC
Permalink
Post by Lawrence D'Oliveiro
Post by Arne Vajhøj
That code would look a lot cleaner if the do while(false) loop got
removed and the relevant breaks got replaced by goto's.
Show us how you would do it. I can take you through my code step by step,
block by block, if that will help.
As I posted in my other message (untested):

#define PY_SSIZE_T_CLEAN
#include <Python.h>
#include <stdio.h>

static PyObject *
discipline_makedict(PyObject *self, PyObject *args)
{
PyObject *items;
const char *msg = NULL;

const int parsed_ok = PyArg_ParseTuple(args, "Os", &items, &msg);
if (!parsed_ok)
return NULL;

printf("makedict says: \xe2\x80\x9c%s\xe2\x80\x9d\n", msg);
if (!PyTuple_Check(items)) {
PyErr_SetString(PyExc_TypeError, "expecting a tuple");
return NULL;
}
const ssize_t nitems = PyTuple_Size(items);
if (PyErr_Occurred())
return NULL;

PyObject *result = PyDict_New();
if (result == NULL)
return NULL;

for (ssize_t i = 0; i < nitems; ++i) {
PyObject *const item = PyTuple_GetItem(items, i);
if (item == NULL)
break;
if (!PyTuple_Check(item) || PyTuple_Size(item) != 2) {
PyErr_SetString(PyExc_TypeError, "expecting a 2-tuple");
break;
}
PyObject *const first = PyTuple_GetItem(item, 0);
if (first == NULL)
break;
PyObject *const second = PyTuple_GetItem(item, 1);
if (second == NULL)
break;
if (first == (PyObject *)&ExceptMe_type || second == (PyObject *)&ExceptMe_type) {
PyErr_SetString(PyExc_ValueError, "ExceptMe object found");
break;
}
if (PyDict_SetItem(result, first, second) < 0)
break;
}

if (PyErr_Occurred()) {
Py_XDECREF(result);
}

return result;
}

No gotos, no simulated goto-via-early-break in a do/while(false)
loop.

As I said previously, this is more idiomatic, simpler, easier to
reason about, easier to read, and uses fewer variables. Your
initial code was, to be blunt, unreadable and truly awful shit.

- Dan C.
Arne Vajhøj
2024-02-02 02:49:56 UTC
Permalink
Post by Lawrence D'Oliveiro
Post by Arne Vajhøj
That code would look a lot cleaner if the do while(false) loop got
removed and the relevant breaks got replaced by goto's.
Show us how you would do it. I can take you through my code step by step,
block by block, if that will help.
It is pretty simple.

do {
allocate(o1);
...
if(...) break;
...
} while(false);
deallocate(o1);

can be done as:

allocate(o1);
...
if(...) goto cleanup;
...
cleanup:
deallocate(o1);

The first piece of code is pretty bad as it confuses the
reader by using a loop and the break is not very
self documenting.

The second piece of code is straight forward to read
despite using goto.

It gets even more clear in the nested case.

do {
allocate(o1);
...
if(...) break;
...
flag = FALSE;
do {
allocate(o2)
...
if(...) {
flag = TRUE;
break;
}
...
}
deallocate(o2)
if(flag) break;
...
} while(false);
deallocate(o1);

vs:

allocate(o1);
...
if(...) goto cleanup_1;
...
allocate(o2);
...
if(...) goto cleanup_1_and_2;
...
cleanup_1_and_2:
deallocate(o2);
cleanup_1:
deallocate(o1);

The nested do while loop is a big mess. The goto solution
is still simple.

Arne
Dave Froble
2024-02-02 03:38:21 UTC
Permalink
Post by Arne Vajhøj
Post by Lawrence D'Oliveiro
Post by Arne Vajhøj
That code would look a lot cleaner if the do while(false) loop got
removed and the relevant breaks got replaced by goto's.
Show us how you would do it. I can take you through my code step by step,
block by block, if that will help.
It is pretty simple.
do {
allocate(o1);
...
if(...) break;
...
} while(false);
deallocate(o1);
allocate(o1);
...
if(...) goto cleanup;
...
deallocate(o1);
The first piece of code is pretty bad as it confuses the
reader by using a loop and the break is not very
self documenting.
The second piece of code is straight forward to read
despite using goto.
It gets even more clear in the nested case.
do {
allocate(o1);
...
if(...) break;
...
flag = FALSE;
do {
allocate(o2)
...
if(...) {
flag = TRUE;
break;
}
...
}
deallocate(o2)
if(flag) break;
...
} while(false);
deallocate(o1);
allocate(o1);
...
if(...) goto cleanup_1;
...
allocate(o2);
...
if(...) goto cleanup_1_and_2;
...
deallocate(o2);
deallocate(o1);
The nested do while loop is a big mess. The goto solution
is still simple.
Arne
Well, I'd use:

Select <something>
Case = "1"
Some code
Case = "2"
Some other code
End Select

No need for the dreaded GoTo statement ...

But even that can be abused.

Got a friend that got carried away with Select and indenting.

When the Select statements got nested a dozen times, and indents became 8-10
tabs, and the code for each CASE was several pages long ...

If the damn code was going to be so massive and complex, he should have just
branched/performed/whatever to a separate place to do all that work.
--
David Froble Tel: 724-529-0450
Dave Froble Enterprises, Inc. E-Mail: ***@tsoft-inc.com
DFE Ultralights, Inc.
170 Grimplin Road
Vanderbilt, PA 15486
Arne Vajhøj
2024-02-02 03:44:56 UTC
Permalink
Post by Dave Froble
Post by Arne Vajhøj
It gets even more clear in the nested case.
    do {
        allocate(o1);
        ...
        if(...) break;
        ...
        flag = FALSE;
        do {
            allocate(o2)
            ...
            if(...) {
                flag = TRUE;
                break;
            }
            ...
        }
        deallocate(o2)
        if(flag) break;
        ...
    } while(false);
    deallocate(o1);
    allocate(o1);
    ...
    if(...) goto cleanup_1;
    ...
    allocate(o2);
    ...
    if(...) goto cleanup_1_and_2;
    ...
    deallocate(o2);
    deallocate(o1);
The nested do while loop is a big mess. The goto solution
is still simple.
Select <something>
    Case = "1"
        Some code
    Case = "2"
        Some other code
End Select
That code does something completely different.
Post by Dave Froble
But even that can be abused.
Got a friend that got carried away with Select and indenting.
When the Select statements got nested a dozen times, and indents became
8-10 tabs, and the code for each CASE was several pages long ...
If the damn code was going to be so massive and complex, he should have
just branched/performed/whatever to a separate place to do all that work.
To quote from Linux kernel coding style doc:

<quote>
Now, some people will claim that having 8-character indentations makes
the code move too far to the right, and makes it hard to read on a
80-character terminal screen. The answer to that is that if you need
more than 3 levels of indentation, you’re screwed anyway, and should fix
your program.

In short, 8-char indents make things easier to read, and have the added
benefit of warning you when you’re nesting your functions too deep. Heed
that warning.
</quote>

Arne
Lawrence D'Oliveiro
2024-02-02 04:51:01 UTC
Permalink
Post by Arne Vajhøj
<quote>
Now, some people will claim that having 8-character indentations makes
the code move too far to the right, and makes it hard to read on a
80-character terminal screen. The answer to that is that if you need
more than 3 levels of indentation, you’re screwed anyway, and should fix
your program.
I think this is a load of nonsense.
Arne Vajhøj
2024-02-02 12:56:33 UTC
Permalink
Post by Lawrence D'Oliveiro
Post by Arne Vajhøj
<quote>
Now, some people will claim that having 8-character indentations makes
the code move too far to the right, and makes it hard to read on a
80-character terminal screen. The answer to that is that if you need
more than 3 levels of indentation, you’re screwed anyway, and should fix
your program.
I think this is a load of nonsense.
Apparently Linus doesn't think so.

And while few may have worded is this blunt, then it is
generally accepted that deep nesting is a code smell and
should be refactored and code moved out to functions/methods.

The specifics may depend a little on the language. 3 may
make sense in C, but VB.NET may justify a higher value
(namespace and class add levels before even getting started
and try catch blocks plus using statements also tend to
add more levels without the levels impacting flow).

Arne
Lawrence D'Oliveiro
2024-02-05 23:25:26 UTC
Permalink
Post by Arne Vajhøj
Post by Lawrence D'Oliveiro
Post by Arne Vajhøj
<quote>
Now, some people will claim that having 8-character indentations makes
the code move too far to the right, and makes it hard to read on a
80-character terminal screen. The answer to that is that if you need
more than 3 levels of indentation, you’re screwed anyway, and should
fix your program.
I think this is a load of nonsense.
Apparently Linus doesn't think so.
I know he doesn’t.
Post by Arne Vajhøj
And while few may have worded is this blunt, then it is generally
accepted that deep nesting is a code smell and should be refactored and
code moved out to functions/methods.
I do deep nesting all the time. This one goes 8 levels deep.

(defun prev_less_indent (count)
"moves to the last prior line with a lesser indentation level."
(interactive "p")
(loop break
(back-to-indentation)
(let
(
(indent_end (point))
indent_amt
line_start
)
(beginning-of-line)
(cond
((> indent_end (point))
(setq indent_amt (- indent_end (point) 1))
(unless
(loop done
(when (= (point) (point-min))
(ding)
(done nil)
) ; when
(previous-logical-line)
(beginning-of-line)
(setq line_start (point))
(end-of-line)
(when (/= line_start (point)) ; skip over empty lines
(back-to-indentation)
(setq indent_end (point))
(beginning-of-line)
(when (< (- indent_end (point)) indent_amt)
(done t)
) ; when
) ; when
) ; loop
(break)
) ; unless
)
(t ; on line with no leading whitespace
(ding)
(break)
)
) ; cond
) ; let
(setq count (- count 1))
(when (<= count 0)
(break)
) ; when
) ; loop
(back-to-indentation)
) ; prev_less_indent

Feel free to show us how it should be “refactored and code moved out
to functions/methods”.
Lawrence D'Oliveiro
2024-02-02 04:50:22 UTC
Permalink
Post by Arne Vajhøj
The nested do while loop is a big mess.
Looks like you are adding a whole lot more lines of code in the form of
jumps and places to jump to, and flags to control what to do when you get
there. Adding a bit of a combinatorial explosion in possible cases that
have to be verified somehow.

In short, you are making a bigger mess.
Arne Vajhøj
2024-02-02 13:44:00 UTC
Permalink
Post by Lawrence D'Oliveiro
Post by Arne Vajhøj
The nested do while loop is a big mess.
Looks like you are adding a whole lot more lines of code in the form of
jumps and places to jump to, and flags to control what to do when you get
there. Adding a bit of a combinatorial explosion in possible cases that
have to be verified somehow.
I "added" lines so that the total number of lines "increased" from
7 to 6 in the one-level example and from 20 to 12 in the two-level
example.

Arne
Lawrence D'Oliveiro
2024-02-05 23:20:29 UTC
Permalink
Post by Lawrence D'Oliveiro
Post by Arne Vajhøj
The nested do while loop is a big mess.
Looks like you are adding a whole lot more lines of code in the form of
jumps and places to jump to, and flags to control what to do when you
get there. Adding a bit of a combinatorial explosion in possible cases
that have to be verified somehow.
I "added" lines so that the total number of lines "increased" from 7 to
6 in the one-level example and from 20 to 12 in the two-level example.
Fine. Now put it all together into a finished example, and show us how it
looks.
Dan Cross
2024-02-02 13:49:57 UTC
Permalink
Post by Lawrence D'Oliveiro
Post by Arne Vajhøj
The nested do while loop is a big mess.
Looks like you are adding a whole lot more lines of code in the form of
jumps and places to jump to, and flags to control what to do when you get
there. Adding a bit of a combinatorial explosion in possible cases that
have to be verified somehow.
In short, you are making a bigger mess.
Again, for this example, the code needs neither goto nor
the abstruse loop structure you wrote. See my earlier
post for details.

- Dan C.
Arne Vajhøj
2024-02-02 13:56:06 UTC
Permalink
Post by Dan Cross
Post by Lawrence D'Oliveiro
Post by Arne Vajhøj
The nested do while loop is a big mess.
Looks like you are adding a whole lot more lines of code in the form of
jumps and places to jump to, and flags to control what to do when you get
there. Adding a bit of a combinatorial explosion in possible cases that
have to be verified somehow.
In short, you are making a bigger mess.
Again, for this example, the code needs neither goto nor
the abstruse loop structure you wrote. See my earlier
post for details.
He cut so much that the context was not obvious.

But his post was a reply to my post with generic
... blocks.

It is true the first specific example he provided
did not need to solve this problem if it was
restructured a little.

Arne
Dan Cross
2024-02-02 15:30:01 UTC
Permalink
Post by Arne Vajhøj
Post by Dan Cross
Post by Lawrence D'Oliveiro
Post by Arne Vajhøj
The nested do while loop is a big mess.
Looks like you are adding a whole lot more lines of code in the form of
jumps and places to jump to, and flags to control what to do when you get
there. Adding a bit of a combinatorial explosion in possible cases that
have to be verified somehow.
In short, you are making a bigger mess.
Again, for this example, the code needs neither goto nor
the abstruse loop structure you wrote. See my earlier
post for details.
He cut so much that the context was not obvious.
But his post was a reply to my post with generic
... blocks.
This seems to be his MO: when presented with an
argument that disconfirms one of his preconceptions,
ignore it and respond to something else, usually
a strawman of his own creation.
Post by Arne Vajhøj
It is true the first specific example he provided
did not need to solve this problem if it was
restructured a little.
Yes. I suspect most of his code similarly.

- Dan C.
Dave Froble
2024-02-01 04:00:35 UTC
Permalink
Post by Arne Vajhøj
Post by Lawrence D'Oliveiro
Post by Lawrence D'Oliveiro
Post by Lawrence D'Oliveiro
I have never written a goto in C code (not production code, anyway). These
days, you need to do so much dynamic allocation, there is nearly always
some need for cleanup when exiting an inner block anyway, so you can’t
just jump directly somewhere else first. The overall pattern looks like
MyPtr obj = NULL;
do /*once*/
{
... possible other stuff ...
«allocate memory for obj»;
if («error occurred»)
break;
... possible other stuff using obj ...
}
while (false);
free(obj);
You can confirm, just by inspection, that there is no path out of the
block that does not pass through the free() call precisely once.
MyPtr obj = NULL;
... possible other stuff ...
«allocate memory for obj»;
if («error occurred»)
goto lbl_freeobj;
... possible other stuff using obj ...
free(obj);
are?
Nesting.
Goto work fine with nested loops. In fact it is one of the cases
where it really makes sense.
Post by Lawrence D'Oliveiro
Try to scale up to something like
static PyObject * discipline_makedict
(
PyObject * self,
PyObject * args
)
{
PyObject * result = NULL;
PyObject * tempresult = NULL;
br_PyObject * items;
const br_char * msg = NULL;
do /*once*/
{
const bool parsed_ok = PyArg_ParseTuple(args, "Os", &items, &msg);
if (not parsed_ok)
break;
fprintf(stdout, "makedict says: “%s”\n", msg);
if (not PyTuple_Check(items))
{
PyErr_SetString(PyExc_TypeError, "expecting a tuple");
break;
} /*if*/
const ssize_t nr_items = PyTuple_Size(items);
if (PyErr_Occurred())
break;
tempresult = PyDict_New();
if (tempresult == NULL)
break;
for (ssize_t i = 0;;)
{
if (i == nr_items)
break;
br_PyObject * const item = PyTuple_GetItem(items, i);
if (item == NULL)
break;
if (not PyTuple_Check(item) or PyTuple_Size(item) != 2)
{
PyErr_SetString(PyExc_TypeError, "expecting a 2-tuple");
break;
} /*if*/
br_PyObject * const first = PyTuple_GetItem(item, 0);
if (first == NULL)
break;
br_PyObject * const second = PyTuple_GetItem(item, 1);
if (second == NULL)
break;
if (first == (PyObject *)&ExceptMe_type or second == (PyObject
*)&ExceptMe_type)
{
PyErr_SetString(PyExc_ValueError, "ExceptMe object found");
break;
} /*if*/
if (PyDict_SetItem(tempresult, first, second) < 0)
break;
++i;
} /*for*/
if (PyErr_Occurred())
break;
/* all done */
result = tempresult;
tempresult = NULL; /* so I don’t dispose of it yet */
}
while (false);
Py_XDECREF(tempresult);
return
result;
} /*discipline_makedict*/
That code would look a lot cleaner if the do while(false) loop got
removed and the relevant breaks got replaced by goto's.
A well named goto label is much more informative than a plain break.
Post by Lawrence D'Oliveiro
More details here
<https://gitlab.com/ldo/a_structured_discipline_of_programming/>.
Truly bad design.
All the code examples would look better with the do while(false) loops
removed and appropriate goto's.
Arne
It's called do whatever to avoid a goto, and it can be very bad ...
--
David Froble Tel: 724-529-0450
Dave Froble Enterprises, Inc. E-Mail: ***@tsoft-inc.com
DFE Ultralights, Inc.
170 Grimplin Road
Vanderbilt, PA 15486
Arne Vajhøj
2024-01-31 15:20:35 UTC
Permalink
Post by Dave Froble
I'm amused every time the GoTo bashing begins.
Not only is there nothing wrong when using a branch operation, when
appropriate, just look at the assembler listings after compilation.
Branching
is just about all assembler does, as required.
Now, I won't defend what I and most consider improper use of the poor
misunderstood GoTo statement.
But unless used very carefully, it can create horrible spaghetti like code, and
is also easy to screw up.
Using proper structured constructs is much better - easier to read as well,
hence better maintainability.
Prey tell, what structured construct will perform cleanup and exit?  I
always expected a return from routines and such.
Let me try and show some examples.

In VB.NET.

Te first two examples could be done in VMS Basic (obviously
procedural not object oriented) but the last can not.

First with goto:

Imports System

Namespace GoToDemo
Public NotInheritable Class Luck
Private Shared rng As New Random()
Public Shared Function InLuck() As Boolean
Return rng.NextDouble() > 0.2
End Function
End Class
Public Class X
Private id As String
Private Sub New(id As String)
Me.id = id
Console.WriteLine("X {0} created", id)
End Sub
Public Shared Function Create(id As String) As X
If Luck.InLuck() Then
Return New X(id)
Else
Return Nothing
End If
End Function
Public Sub Close()
Console.WriteLine("X {0} closed", id)
End Sub
End Class
Public Class Program
Public Shared Sub Main(args As String())
Dim o1 As X = X.Create("A")
If o1 Is Nothing Then
Console.WriteLine("Error creating A")
GoTo lbl_done
End If
Dim o2 As X = X.Create("B")
If o2 Is Nothing Then
Console.WriteLine("Error creating B")
GoTo lbl_close1
End If
' 20 lines
Console.WriteLine("Part 1")
If Not Luck.InLuck() Then
Console.WriteLine("Error during execution")
GoTo lbl_close2
End If
' 20 lines
Console.WriteLine("Part 2")
lbl_close2:
o2.Close()
lbl_close1:
o1.Close()
lbl_done:
Console.ReadKey(True)
End Sub
End Class
End Namespace

It is with goto, but I don't think it is a bad use of goto. It just
jumps down to the cleanup code in case of an error.

Next traditional blocks:

Imports System

Namespace BlocksDemo
Public NotInheritable Class Luck
Private Shared rng As New Random()
Public Shared Function InLuck() As Boolean
Return rng.NextDouble() > 0.2
End Function
End Class
Public Class X
Private id As String
Private Sub New(id As String)
Me.id = id
Console.WriteLine("X {0} created", id)
End Sub
Public Shared Function Create(id As String) As X
If Luck.InLuck() Then
Return New X(id)
Else
Return Nothing
End If
End Function
Public Sub Close()
Console.WriteLine("X {0} closed", id)
End Sub
End Class
Public Class Program
Public Shared Sub Main(args As String())
Dim o1 As X = X.Create("A")
If o1 IsNot Nothing Then
Dim o2 As X = X.Create("B")
If o2 IsNot Nothing Then
' 20 lines
Console.WriteLine("Part 1")
If Luck.InLuck() Then
' 20 lines
Console.WriteLine("Part 2")
Else
Console.WriteLine("Error during execution")
End If
o2.Close()
Else
Console.WriteLine("Error creating B")
End If
o1.Close()
Else
Console.WriteLine("Error creating A")
End If
Console.ReadKey(True)
End Sub
End Class
End Namespace

No goto's. But I do not consider the code more readable than the
version with goto's. It sort of unnecessarily stretch out the
core logic.

And now the modern way with exceptions:

Imports System

Namespace ExceptionsDemo
Public NotInheritable Class Luck
Private Shared rng As New Random()
Public Shared Function InLuck() As Boolean
Return rng.NextDouble() > 0.2
End Function
End Class
Public Class XException
Inherits Exception
Public Sub New(msg As String)
MyBase.New(msg)
End Sub
End Class
Public Class X
Implements IDisposable
Private id As String
Public Sub New(id As String)
If Luck.InLuck() Then
Me.id = id
Console.WriteLine("X {0} created", id)
Else
Throw New XException("Error creating " & id)
End If
End Sub
Public Sub Dispose() Implements IDisposable.Dispose
Console.WriteLine("X {0} closed", id)
End Sub
End Class
Public Class Program
Public Shared Sub Main(args As String())
Try
Using o1 As New X("A")
Using o2 As New X("B")
' 20 lines
Console.WriteLine("Part 1")
If Not Luck.InLuck() Then
Throw New XException("Error during execution")
End If
' 20 lines
Console.WriteLine("Part 2")
End Using
End Using
Catch ex As XException
Console.WriteLine(ex.Message)
End Try
Console.ReadKey(True)
End Sub
End Class
End Namespace

Which I think is pretty nice. No goto's but still a compact
core logic.

For the not VB.NET knowledgable:

Using o1 As New X("A")
...
End Using

calls o1.Dispose() when the block is exited no matter how it
is exited - normal or exception does not matter Dispose is
always called.

Arne
Simon Clubley
2024-01-31 18:22:37 UTC
Permalink
Post by Arne Vajhøj
Using o1 As New X("A")
...
End Using
calls o1.Dispose() when the block is exited no matter how it
is exited - normal or exception does not matter Dispose is
always called.
Unless there is a power failure or a system crash.

I wonder how many people think of that one when assuming that their
state reset code will _always_ run after execution of the routine
has started. :-)

Simon.
--
Simon Clubley, ***@remove_me.eisner.decus.org-Earth.UFP
Walking destinations on a map are further away than they appear.
Arne Vajhøj
2024-01-31 18:38:32 UTC
Permalink
Post by Simon Clubley
Post by Arne Vajhøj
Using o1 As New X("A")
...
End Using
calls o1.Dispose() when the block is exited no matter how it
is exited - normal or exception does not matter Dispose is
always called.
Unless there is a power failure or a system crash.
I guess that is also a form of exit.

:-)
Post by Simon Clubley
I wonder how many people think of that one when assuming that their
state reset code will _always_ run after execution of the routine
has started. :-)
Probably none. But it probably does not matter either.

The construct is used to free unmanaged resources in the
process. Open files, open network connections like database
connections, unmanaged memory etc.. All stuff that goes
away if the process is gone.

I have never seen the construct used to reset an out
of process state (persisted state). And I have seen
a lot of C#, VB.NET, Java, Python etc. code using the
construct.

If there is a need for a consistent out of process
state (persisted state), then it has to be transactions.

Arne
Lawrence D'Oliveiro
2024-01-31 21:24:14 UTC
Permalink
Post by Arne Vajhøj
Using o1 As New X("A")
...
End Using
calls o1.Dispose() when the block is exited no matter how it is exited -
normal or exception does not matter Dispose is always called.
Python has “context managers” which are a generalization of this. It also
has “try/finally” blocks, which are good for one-off cases.
Arne Vajhøj
2024-01-31 22:13:26 UTC
Permalink
Post by Lawrence D'Oliveiro
Post by Arne Vajhøj
Using o1 As New X("A")
...
End Using
calls o1.Dispose() when the block is exited no matter how it is exited -
normal or exception does not matter Dispose is always called.
Python has “context managers” which are a generalization of this. It also
has “try/finally” blocks, which are good for one-off cases.
C# was born with using (2002), Python got with in 2.5 (2006)
and Java got try with resource in 1.7 (2011).

MS got a good idea and the rest copied it.

Arne
Lawrence D'Oliveiro
2024-01-31 23:18:12 UTC
Permalink
Post by Arne Vajhøj
Post by Lawrence D'Oliveiro
Post by Arne Vajhøj
Using o1 As New X("A")
...
End Using
calls o1.Dispose() when the block is exited no matter how it is exited -
normal or exception does not matter Dispose is always called.
Python has “context managers” which are a generalization of this. It also
has “try/finally” blocks, which are good for one-off cases.
C# was born with using (2002), Python got with in 2.5 (2006)
and Java got try with resource in 1.7 (2011).
MS got a good idea and the rest copied it.
That is also true of async/await. But note that Python is the only one
of the three that tries to use reference-counting as an alternative to
garbage collection.

And now it looks like C# might be shuffling off into those retirement
pastures
<https://www.theregister.com/2024/01/31/microsoft_seeks_rust_developers/>.
Arne Vajhøj
2024-02-01 00:42:50 UTC
Permalink
Post by Lawrence D'Oliveiro
Post by Arne Vajhøj
Post by Lawrence D'Oliveiro
Post by Arne Vajhøj
Using o1 As New X("A")
...
End Using
calls o1.Dispose() when the block is exited no matter how it is exited -
normal or exception does not matter Dispose is always called.
Python has “context managers” which are a generalization of this. It also
has “try/finally” blocks, which are good for one-off cases.
C# was born with using (2002), Python got with in 2.5 (2006)
and Java got try with resource in 1.7 (2011).
MS got a good idea and the rest copied it.
That is also true of async/await. But note that Python is the only one
of the three that tries to use reference-counting as an alternative to
garbage collection.
All of them use garbage collection.

Java and C# use tracing garbage collection.

Python use both tracing garbage collection and reference
counting garbage collection. Or more precisely the common
implementation CPython does - there are other Python
implementations that use only tracing garbage collection.
Post by Lawrence D'Oliveiro
And now it looks like C# might be shuffling off into those retirement
pastures
<https://www.theregister.com/2024/01/31/microsoft_seeks_rust_developers/>.
Very interesting for Rust, but not particular important for C#.

C# is primarily for business applications.

That Microsoft will rewrite some platform software supporting
moving data within Office 365 in Azure from C# to Rust does
not indicate the end of C#.

I would consider it more negative for Go. Go is big in that
type of cloud and/or container platform software, so MS not
picking Go may indicate something.

Arne
Yoty Randy
2024-02-01 01:00:26 UTC
Permalink
TELEGRAM link
https://t.me/YotyRandy842
https://t.me/YotyRandy842

We have many products on DMT, LSD, MDMA, Psilocybin Magic mushrooms, cannabis, and microdosing psychedelics. Buy Highest Quality DMT Carts, XTC Pills, LSD Edibles, Shrooms Chocolates, Psychedelics Magic Mushrooms Gummies Online In USA ✓ Great Prices ✓ Trusted psychedelics vendor with tracking ✓ Fast Delivery worldwide.

US-US Delivery
Fast Shipping
Secure Payment Options
100% Satisfaction Guaranteed
3 Days Refund Policy
100% Money-Back if any issue with the product
Shipping Service: Overnight/Standard/Economy
Estimated Delivery Time: Overnight & 3-5 Days
Discounts: Get up to 20% off
Shipping Rates – USPS: $30 FedEx: $45 Only USA.
Pay With Credit / Debit Cards Also
CLICK ➤HERE ➤TO ➤BUY ➤DMT➤ONLINE


We sell the highest-quality DMT vape cartridges, LSD edibles, and Psilocybin chocolate bars for microdosing, with a focus on sourcing from premium suppliers.



Telegram link
https://t.me/YotyRandy842

Buy DMT Vape Cartridges And Microdose DMT USA Online
https://t.me/YotyRandy842
https://t.me/YotyRandy842

Buy LSD Microdoses And LSD Edibles Online

Buy Psilocybin Mushroom And Mushroom Microdoses

Buy 100ML 4-ACO-DMT Microdosing Kit

Buy 5-MeO DMT .5ml Purecybin Carts:

https://t.me/YotyRandy842
https://t.me/YotyRandy842

Buy 4-AcO-DMT Freebase:

https://t.me/YotyRandy842

Buy 5-MeO-DMT Cartridge 1mL:

https://t.me/YotyRandy842
https://t.me/YotyRandy842
Buy Deadhead Chemist DMT (Vape and Cartridge) 1mL:

Buy DeadHead Chemist DMT Vape Cartridge:

Buy DMT .5ml Purecybin – 300mg DMT
https://t.me/YotyRandy842

Buy DMT (Free Base)DMT 1ml 800mg DMT Vape – Mushrooms Canada
https://t.me/YotyRandy842
Lawrence D'Oliveiro
2024-02-01 02:50:41 UTC
Permalink
Post by Arne Vajhøj
C# is primarily for business applications.
Never heard of it being used for anything important. For example,
Microsoft would never use it itself in Office.
Arne Vajhøj
2024-02-02 03:11:20 UTC
Permalink
Post by Lawrence D'Oliveiro
Post by Arne Vajhøj
C# is primarily for business applications.
Never heard of it being used for anything important. For example,
Microsoft would never use it itself in Office.
It is correct that MS never rewrote MSO from C++ to C#.
They did port VS to C# though.

But C# is all over. Finance, e-commerce, government etc..

The one C# app that I suspect that everyone here has used
is Wikipedia search. Wikipedia choose to do their search
using Lucene.NET instead of normal Lucene (Java based).

Arne
Lawrence D'Oliveiro
2024-02-02 04:48:28 UTC
Permalink
Post by Arne Vajhøj
Post by Lawrence D'Oliveiro
Post by Arne Vajhøj
C# is primarily for business applications.
Never heard of it being used for anything important. For example,
Microsoft would never use it itself in Office.
It is correct that MS never rewrote MSO from C++ to C#.
They did port VS to C# though.
Maybe, but VS Code takes an entirely different tack, using Electron (the
Chromium engine + TypeScript/JavaScript) instead. Wonder why?
Post by Arne Vajhøj
But C# is all over. Finance, e-commerce, government etc..
All that stuff that’s now in the cloud?
Arne Vajhøj
2024-02-02 12:38:14 UTC
Permalink
Post by Lawrence D'Oliveiro
Post by Arne Vajhøj
Post by Lawrence D'Oliveiro
Post by Arne Vajhøj
C# is primarily for business applications.
Never heard of it being used for anything important. For example,
Microsoft would never use it itself in Office.
It is correct that MS never rewrote MSO from C++ to C#.
They did port VS to C# though.
Maybe, but VS Code takes an entirely different tack, using Electron (the
Chromium engine + TypeScript/JavaScript) instead. Wonder why?
VSC was intended to compete with Atom on Windows/Linux/macOS. VSC
was released before .NET Core. So MS did not have much of a choice.
Post by Lawrence D'Oliveiro
Post by Arne Vajhøj
But C# is all over. Finance, e-commerce, government etc..
All that stuff that’s now in the cloud?
A lot of it.

But C# does not care if if the hardware it runs on is
bought or rented.

Arne
Arne Vajhøj
2024-02-02 12:42:22 UTC
Permalink
Post by Arne Vajhøj
Post by Lawrence D'Oliveiro
Post by Arne Vajhøj
It is correct that MS never rewrote MSO from C++ to C#.
They did port VS to C# though.
Maybe, but VS Code takes an entirely different tack, using Electron (the
Chromium engine + TypeScript/JavaScript) instead. Wonder why?
VSC was intended to compete with Atom on Windows/Linux/macOS. VSC
was released before .NET Core. So MS did not have much of a choice.
Correction: they had lots of choices, but C# was just not one of them.

Arne
Lawrence D'Oliveiro
2024-02-04 22:51:30 UTC
Permalink
Post by Arne Vajhøj
Post by Lawrence D'Oliveiro
Post by Arne Vajhøj
But C# is all over. Finance, e-commerce, government etc..
All that stuff that’s now in the cloud?
A lot of it.
But C# does not care if if the hardware it runs on is bought or rented.
Looks like Microsoft now wants to get rid of at least some of its own C#
code. It is looking for developers to convert it to Rust.

Not exactly a vote of confidence in the future of C#/Dotnet, is it?
Stephen Hoffman
2024-01-31 16:05:22 UTC
Permalink
Post by Dave Froble
Post by Dave Froble
Post by Arne Vajhøj
Post by k***@panix.com
Post by Arne Vajhøj
The code is VB6.
But none of the problems are Basic specific. It is possible
to write the same bad code in C or Fortran or whatever.
So it just shows that there are some really really bad programmers out
there.
I have worked with people who could write spaghetti Fortran in any
programming language available.
"A real Fortran programmer can write Fortran in any language"
PROGRAM GOTOFUN(INPUT,OUTPUT);
LABEL L731,L113,L247,L588,L761,L922,L399,L601;
VAR LBL:INTEGER;
VAR I:INTEGER;
BEGIN
L731: GOTO L113;
LBL:=399;
L113: I:=0;
WRITELN(I);
L247: LBL:=601;
IF(I<0)THEN GOTO L588 ELSE IF(I=0)THEN GOTO L922 ELSE GOTO L399;
L588: I:=I+1;
WRITELN(I);
GOTO L399;
L761: CASE(LBL)OF 399: GOTO L399; 601: GOTO L601; END;
L922: I:=I+1;
WRITELN(I);
CASE(I)OF 1: GOTO L588; 2: GOTO L399; 3: GOTO L922; END;
L399: GOTO L761;
L601: END.
:-)
Arne
I'm amused every time the GoTo bashing begins.
Not only is there nothing wrong when using a branch operation, when
appropriate, just look at the assembler listings after compilation. Branching
is just about all assembler does, as required.
Now, I won't defend what I and most consider improper use of the poor
misunderstood GoTo statement.
But unless used very carefully, it can create horrible spaghetti like code, and
is also easy to screw up.
Using proper structured constructs is much better - easier to read as well,
hence better maintainability.
Prey tell, what structured construct will perform cleanup and exit? I
always expected a return from routines and such.
BASIC has its own variation on the classic TRY / THROW / CATCH /
FINALLY syntax:
WHEN ERROR IN
protected-statement [protected-statement,...]
USE
handler-statement [handler-statement,...]
END WHEN

But I'm mildly surprised it's lacking an ATEXIT or ilk. (I thought it
had that now, but I'm clearly mis-remembering.) I've used $dclexh and
ilk in various apps, or coded the app to release at rundown. (Not that
I prefer to have to implement manual cleanup, much as I'd like to avoid
explicitly deallocating memory in C. Garbage collection is so much
nicer, outside of kernel mode or other special app or context
requirements.)
Classic BASIC, Fortran, and C tend to be pretty bad at this
error-handling stuff (it's kinda been grafted on) without a fair amount
of work by the developer, and quite possibly with platform-specific
calls ($dclexh, etc) added. (Yes, I know about setjmp, atexit(), etc.
in C, and some other error-related syntax.) And yes, in BASIC, that
GOTO is one of the common ways to deal with errors, but I'd usually go
WHEN ERROR IN where I can. Or whatever other TRY / THROW / CATCH /
FINALLY / ATEXIT exists in the particular implementation.

And as for that earlier BASIC line number gibe, I'm sure most folks
working with BASIC on OpenVMS nowadays are using labels, as the labels
are just vastly more descriptive.

I've long thought this: "If the ERR function is used before an error
occurs or after an error is handled, the results are undefined" was
silly. UB? Seriously? Return some analog to SS$_NORMAL. Poof. No UB.
--
Pure Personal Opinion | HoffmanLabs LLC
Lawrence D'Oliveiro
2024-01-31 21:22:33 UTC
Permalink
(Not that I prefer to have to implement manual cleanup, much as I'd like
to avoid explicitly deallocating memory in C.
Note that free(3) is defined as idempotent; freeing a NULL pointer is a
harmless no-op. That simplifies things a lot.
Stephen Hoffman
2024-02-02 21:43:15 UTC
Permalink
Post by Lawrence D'Oliveiro
(Not that I prefer to have to implement manual cleanup, much as I'd
like to avoid explicitly deallocating memory in C.
Note that free(3) is defined as idempotent; freeing a NULL pointer is a
harmless no-op. That simplifies things a lot.
Pragmatically, the difference between (pseudo-code) free(xyz) where xyz
is nulllptr or ((void*)0) or whatever, and the same brute-force if
(xyz) free(xyz); code, or a macro of same, is negligible.

No, that free ignores a null doesn't simplify the bookkeeping. There
are other languages that are easier here.

Though semi-similarly, sending a null at a method in Objective C can be
useful. And can be a source of confusion and bugs.

On OpenVMS, using VM zones reduces the memory management bookkeeping in
some contexts, as the whole zone can be freed in one shot. This
technique can be handy for command parsers, where you know you're done
with ~everything parsing-related when you're parsing the next command.

There are other trade-offs that can make this effort easier, not the
least of which is garbage collection.

Apropos of nothing, asctime() and ctime() are now (C23) deprecated.

And some semi-related reading: https://jorengarenar.github.io/blog/less-known-c
--
Pure Personal Opinion | HoffmanLabs LLC
Lawrence D'Oliveiro
2024-02-03 01:48:30 UTC
Permalink
Post by Stephen Hoffman
No, that free ignores a null doesn't simplify the bookkeeping.
It does though, in the code example I have posted elsewhere. You can just
put a sequence of unconditional free(3) calls, which is much shorter than
useless things like

if (ptr)
free(ptr);

which I see all too often.

By the way, the C++ “delete” statement is similarly specified to treat an
attempt to dispose of a NULL pointer as a harmless no-op.
Arne Vajhøj
2024-01-30 23:54:17 UTC
Permalink
Post by Dave Froble
Post by Arne Vajhøj
Post by k***@panix.com
I have worked with people who could write spaghetti Fortran in any
programming language available.
"A real Fortran programmer can write Fortran in any language"
      PROGRAM GOTOFUN(INPUT,OUTPUT);
I'm amused every time the GoTo bashing begins.
Not only is there nothing wrong when using a branch operation, when
appropriate, just look at the assembler listings after compilation.
Branching is just about all assembler does, as required.
Now, I won't defend what I and most consider improper use of the poor
misunderstood GoTo statement.
The IT world 50-60 years ago had a GoTo problem.

The lack of structured constructs in assembler, Fortran 66,
original Dartmouth Basic etc. had resulted in a lot of
spaghetti code.

And as a result GoTo got a very bad reputation.

The IT world today does not have a GoTo problem.

Many languages does not support GoTo, but even in the languages
that do support GoTo it is typical not a common construct.

There are actual cases where GoTo (goto in case sensitive languages)
can result in more readable code than the structured approach.

In languages without exception support then a goto down to
cleanup code can be very readable.

In languages without labeled break then a goto out of an
inner loop can be very readable.

Arne
bill
2024-01-30 16:45:43 UTC
Permalink
Post by k***@panix.com
Post by Arne Vajhøj
The code is VB6.
But none of the problems are Basic specific. It is possible
to write the same bad code in C or Fortran or whatever.
So it just shows that there are some really really bad programmers out
there.
I have worked with people who could write spaghetti Fortran in any
programming language available. Did you know that LISP has a goto?
It does.
Post by Arne Vajhøj
PS: Good compilers may have detected the unreachable code. But it
is still good vs bad compiler not good vs bad language.
The exciting part is when they tell you not to remove the unreachable code,
because the program crashes at runtime when you do that.
Many moons ago I had to try to fix a number of programs that
crashed whenever run. Back in those days a common method was
to add statements to display variables during execution. I
had many cases where adding those statements made the program
work.

bill
Chris Townley
2024-01-30 17:14:21 UTC
Permalink
Post by bill
Post by k***@panix.com
Post by Arne Vajhøj
The code is VB6.
But none of the problems are Basic specific. It is possible
to write the same bad code in C or Fortran or whatever.
So it just shows that there are some really really bad programmers out
there.
I have worked with people who could write spaghetti Fortran in any
programming language available.  Did you know that LISP has a goto?
It does.
Post by Arne Vajhøj
PS: Good compilers may have detected the unreachable code. But it
     is still good vs bad compiler not good vs bad language.
The exciting part is when they tell you not to remove the unreachable code,
because the program crashes at runtime when you do that.
Many moons ago I had to try to fix a number of programs that
crashed whenever run.  Back in those days a common method was
to add statements to display variables during execution.  I
had many cases where adding those statements made the program
work.
bill
Could it have been the variables were being incorrectly being optimised
out, but adding a print statement would avoid that. I have seen that a
few times
--
Chris
bill
2024-01-30 17:24:51 UTC
Permalink
Post by Chris Townley
Post by bill
Post by k***@panix.com
Post by Arne Vajhøj
The code is VB6.
But none of the problems are Basic specific. It is possible
to write the same bad code in C or Fortran or whatever.
So it just shows that there are some really really bad programmers out
there.
I have worked with people who could write spaghetti Fortran in any
programming language available.  Did you know that LISP has a goto?
It does.
Post by Arne Vajhøj
PS: Good compilers may have detected the unreachable code. But it
     is still good vs bad compiler not good vs bad language.
The exciting part is when they tell you not to remove the unreachable code,
because the program crashes at runtime when you do that.
Many moons ago I had to try to fix a number of programs that
crashed whenever run.  Back in those days a common method was
to add statements to display variables during execution.  I
had many cases where adding those statements made the program
work.
bill
Could it have been the variables were being incorrectly being optimised
out, but adding a print statement would avoid that. I have seen that a
few times
Usually it had to do with out of range access. Adding the displays
enlarged the I Area changing the location being accessed. Didn't
fix the program but made it run enough to troubleshoot once you knew
what the problem probably was.

bill
Scott Dorsey
2024-01-31 00:16:09 UTC
Permalink
Post by bill
Many moons ago I had to try to fix a number of programs that
crashed whenever run. Back in those days a common method was
to add statements to display variables during execution. I
had many cases where adding those statements made the program
work.
Yes, this is a sign of a fandango on core. In Fortran it is
likely exceeding array bounds or bad parameter passing, but in
C the possibilities to screw up with pointers are endless.
--scott
--
"C'est un Nagra. C'est suisse, et tres, tres precis."
bill
2024-01-31 01:21:43 UTC
Permalink
Post by Scott Dorsey
Post by bill
Many moons ago I had to try to fix a number of programs that
crashed whenever run. Back in those days a common method was
to add statements to display variables during execution. I
had many cases where adding those statements made the program
work.
Yes, this is a sign of a fandango on core. In Fortran it is
likely exceeding array bounds or bad parameter passing, but in
C the possibilities to screw up with pointers are endless.
Bingo!!!

It was mostly Fortran but every once in a while some idiot
would do it in COBOL, too.

By the way, the Fortran was what you get when you have Electrical
and Mechanical engineers with too much time on their hands and you
decide to keep them busy by making them write business programs.

bill
Bob Eager
2024-01-31 09:54:15 UTC
Permalink
Post by bill
Many moons ago I had to try to fix a number of programs that crashed
whenever run. Back in those days a common method was to add
statements to display variables during execution. I had many cases
where adding those statements made the program work.
Yes, this is a sign of a fandango on core. In Fortran it is likely
exceeding array bounds or bad parameter passing, but in C the
possibilities to screw up with pointers are endless.
Bingo!!!
It was mostly Fortran but every once in a while some idiot would do it
in COBOL, too.
We had a machine that ran FORTRAN for the physics department. One guy had
a program that crashed the machine. As in, the microcode halted. That was
an array bounds error.

Full story:

http://www.bobeager.uk/anecdotes.html#hwhack
Lawrence D'Oliveiro
2024-01-31 21:21:10 UTC
Permalink
Post by Bob Eager
We had a machine that ran FORTRAN for the physics department. One guy
had a program that crashed the machine. As in, the microcode halted.
That was an array bounds error.
http://www.bobeager.uk/anecdotes.html#hwhack
We contacted ICL, but we never seemed to reach anyone who either
understood what the problem was, or had the power or inclination
to get it fixed ...

If this was not after the Fujitsu acquisition, I assume it wasn’t long
before ...
Michael S
2024-01-31 21:43:40 UTC
Permalink
On Wed, 31 Jan 2024 21:21:10 -0000 (UTC)
Post by Lawrence D'Oliveiro
Post by Bob Eager
We had a machine that ran FORTRAN for the physics department. One
guy had a program that crashed the machine. As in, the microcode
halted. That was an array bounds error.
http://www.bobeager.uk/anecdotes.html#hwhack
We contacted ICL, but we never seemed to reach anyone who either
understood what the problem was, or had the power or inclination
to get it fixed ...
If this was not after the Fujitsu acquisition, I assume it wasn’t
long before ...
From the article it looks like 1980, probably H1.
Andreas Eder
2024-02-03 17:26:38 UTC
Permalink
Post by bill
Post by k***@panix.com
Post by Arne Vajhøj
The code is VB6.
But none of the problems are Basic specific. It is possible
to write the same bad code in C or Fortran or whatever.
So it just shows that there are some really really bad programmers out
there.
I have worked with people who could write spaghetti Fortran in any
programming language available. Did you know that LISP has a goto?
It does.
Post by Arne Vajhøj
PS: Good compilers may have detected the unreachable code. But it
is still good vs bad compiler not good vs bad language.
The exciting part is when they tell you not to remove the unreachable code,
because the program crashes at runtime when you do that.
Many moons ago I had to try to fix a number of programs that
crashed whenever run. Back in those days a common method was
to add statements to display variables during execution. I
had many cases where adding those statements made the program
work.
bill
So it was a Heisenbug :-)

'Andreas
bill
2024-02-03 18:35:09 UTC
Permalink
Post by Andreas Eder
Post by bill
Post by k***@panix.com
Post by Arne Vajhøj
The code is VB6.
But none of the problems are Basic specific. It is possible
to write the same bad code in C or Fortran or whatever.
So it just shows that there are some really really bad programmers out
there.
I have worked with people who could write spaghetti Fortran in any
programming language available. Did you know that LISP has a goto?
It does.
Post by Arne Vajhøj
PS: Good compilers may have detected the unreachable code. But it
is still good vs bad compiler not good vs bad language.
The exciting part is when they tell you not to remove the unreachable code,
because the program crashes at runtime when you do that.
Many moons ago I had to try to fix a number of programs that
crashed whenever run. Back in those days a common method was
to add statements to display variables during execution. I
had many cases where adding those statements made the program
work.
bill
So it was a Heisenbug :-)
Now, that's a very interesting way to look at it. :-)

bill
James Pemberton
2024-02-04 04:09:25 UTC
Permalink
Buy all your psychedelic products with me including clone cards
All products are available for deliveries and drop offs
Fast shipping and delivery of packages to all locations worldwide
Let me know with your orders
Text me on telegram @Only1cross
You can also join my channel for more products and reviews,link below

https://t.me/trippycross2
https://t.me/trippycross2
https://t.me/trippycross2
https://t.me/trippycross2

You can let me know anytime with your orders
Prices are also slightly negotiable depending on the quantity needed
Loading...