[Info-vax] BASIC (and Horizon)
Arne Vajhøj
arne at vajhoej.dk
Wed Jan 31 19:29:14 EST 2024
On 1/31/2024 6:21 PM, Lawrence D'Oliveiro wrote:
> On Wed, 31 Jan 2024 17:08:44 -0500, Arne Vajhøj wrote:
>
>> On 1/31/2024 4:28 PM, Lawrence D'Oliveiro wrote:
>>
>>> 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.
>>
>> 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?
>
> Nesting.
Goto work fine with nested loops. In fact it is one of the cases
where it really makes sense.
> 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.
> 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
More information about the Info-vax
mailing list