Recent

Author Topic: Making a plea :)  (Read 6570 times)

marcov

  • Administrator
  • Hero Member
  • *
  • Posts: 11941
  • FPC developer.
Re: Making a plea :)
« Reply #30 on: October 03, 2024, 04:24:44 pm »
That doesn't make it a good thing. It just means that there is a lot of mindless copying of basic syntax in the hope that such superficial similarities convinces managers to wrongly assume that saves on retraining.

Maybe. I'd like to see a comprehensive poll of programmers and if they struggle with dislike inline vars.

That would be pointless since the average programmer is not aware of such problems. The only thing they know is copying features from other languages, preferably if these save a few keystrokes. So such polls would only lead to confirmation bias by mob rule.

Ask yourself why all feature requests here are copying of rather shallow syntax changes that improve notation or keystrokes, usually local to the place where they are used.

Where are the features that are needed deep inside a framework, and really enable whole new concepts and code in an application wide matter? Other than a few remarks of Warfley (wrt to generics and STL) I haven't heard much.

You need people with some knowledge of language implementation and, preferably having walked on both sides of the fence to do language development. Polling a developer convention is not one of them.

And then I'm not even bringing in the old chestnut that if syntax even if A is better than B, usually having them both is the worst of all.

Quote
My guess is no because new languages that have had decades of experience with C have not identified this one area as problematic. People have endless complains with C in 2024 but I never heard inline vars as one of them.

Then read this thread better, the linux kernel policy has been mentioned already.
« Last Edit: October 03, 2024, 04:26:50 pm by marcov »

Warfley

  • Hero Member
  • *****
  • Posts: 1758
Re: Making a plea :)
« Reply #31 on: October 03, 2024, 04:26:05 pm »
2. Simplifying long expression and function calls

Being able to introduce easily a tight-scoped variable can be a massive boost on readability AND debuggability

Code: Pascal  [Select][+][-]
  1. begin
  2.    var x := ...some longish expression that computes x...;
  3.    var y := ...some expression with side effects that computes y...;
  4.    MyFunction(x, y);
  5. end;

Even with just two variables, the above code allows to spread parameter evaluations cleanly, and it becomes trivial to breakpoint the code after a particular argument is computed and eval the value.
It also brings to the table the ability to name the argument, which can be a significant boost to code readability for functions with many parameters, or functions you're unfamiliar with the order of parameters.
It seems to me that you don't want actual variables here, but defines:
Code: Pascal  [Select][+][-]
  1. {$define x:=long expression1}
  2. {$define y:=long expression2}
  3. fun(x, y);

No need to add any new featrue to the compiler for this

Quote
3. Record initialization

Rather than the legacy variable + fillchar dance, with risk for error and need to read multiple lines of the code, you can just do

var myDescriptor := Default(TSomeDescriptor);
myDescriptor.Field:= 123;
...

I took the descriptor structure exemple, as it's common in APIs. The inline declaration makes everything local and obvious to whoever will read the code.
Since FPC supports managed types, you should avoid any use of FillChar to begin with. And also, don't use Default, it's broken. If you want to correctly initialize a local variable call finalize-initialize:
Code: Pascal  [Select][+][-]
  1. finalize(myVar);
  2. initialize(myVar);

But also, thats what record constructors are for. Just create a function that takes the values for the fields as argument and creates you a record from it:
Code: Pascal  [Select][+][-]
  1. myDescriptor := Descriptor(123);
No need to introduce temporary variables to begin with.

Quote
4. Elimination of the "catalog of variables" anti-pattern

Every function implementation where you have many variables (like in the above points) quickly becomes a massive catalog of variables declaration, followed by implementation. This declarations are not visible without scrolling, and since you have many of them, they're not always readable.

When faced with unfamiliar code, the catalog anti-pattern can also make it non-obvious what a symbol is when reading code: is it a local variable ? an argument ? a property ? something else ?
This can be alleviated by prefixing symbol names, but there will still remain a degree of ambiguity about variable type and scope (esp with nested functions, anonymous procs, where the prefixing is not enough).

Bringing the declaration close to usage just cleans everything up, and makes local portion of code readable and understandable in isolation, which is a huge boon.
To quote the Linux Kernel style guide:
Quote
Another measure of the function is the number of local variables. They shouldn’t exceed 5-10, or you’re doing something wrong. Re-think the function, and split it into smaller pieces.

So yes a catalog of variables is bad, but not because they are all defined in one place, but because having complex functions is bad. If you have to many local variables, the solution is not to hide the problem by putting them all in inline variables, the solution is to restructure your code.

The anti-pattern here is writing to complex functions and trying to hide the complexity. Not the language feature that makes assessing the complexity of a function very easy.

Quote
5. Avoiding uninitialized variables

I'm placing this last because the compiler can help here, so it's not always fatal. Though there will still be a degree of ambiguity when a variable is passed by reference, or when a variable goes out of logic scope, since it can't get out of compiler scope.

Using nested functions is the only mitigation with legacy Pascal, but it's like using a hammer to swipe a mosquito, and it can be detrimental to readability, as it will break the flow of code.
It's actually not really an issue at least when you compile with -Oodfa (data flow analysis). This will show you when a variable is not initialized. Note that passing by reference via a "var" parameter, still technically requires initialization, only passing by reference in an "out" parameter is for uninitialized variables (that said functions like Move use var instead of out, probably due to backwards compatibility, this of course causes an issue)

There are only two good use-cases for inline variables, one is scoping for managed types, which I would much rather see with a specific construct such as python with:
Code: Pascal  [Select][+][-]
  1. with OpenFile as fl do
  2. begin
  3.   // Use fl
  4. end; //After with block fl will be finalized
And for loops, because loop variables are usually quite meaningless (as often indicated by meaningless names such as "i", "j", "k", etc.)

Thaddy

  • Hero Member
  • *****
  • Posts: 16177
  • Censorship about opinions does not belong here.
Re: Making a plea :)
« Reply #32 on: October 03, 2024, 04:30:09 pm »

Quote
5) Anything else? Maybe non-zero based arrays with a range? There may be more.

Yes, the fundamental problem: the language is far too big: bigger than PL/I and Ada which in their day were considered to be oversized.

MarkMLl
Code: Pascal  [Select][+][-]
  1. program ra;
  2. type
  3.  tmyrange  = -4..7;
  4. var
  5.   a:array[tmyrange] of integer;
  6. begin
  7.   writeln(low(a):2,high(a):2);
  8. end.
That kind of thing is what I referred to: it is simply already there...
« Last Edit: October 03, 2024, 04:39:20 pm by Thaddy »
If I smell bad code it usually is bad code and that includes my own code.

Warfley

  • Hero Member
  • *****
  • Posts: 1758
Re: Making a plea :)
« Reply #33 on: October 03, 2024, 04:36:09 pm »
I really would like to hear a detailed expiation of why the Linux kernel has that requirement and what specific problems they had. This may have been an idea the creator had personally and imposed top down. If not I would expect new languages to have abandoned the declare anywhere variables but I've never heard a person complain about them except long time Pascal programers.

There are a few reasons for this, but one, as I explained already in the last thread to a post of yours is that the Linux kernel style guide requires functions of low complexity. And as a measure of complexity they use number of local variables. So by defining them in the beginning of the function, you have a clear indicator of the complexity of the function before having read a single line of actual logic code.

And with respect to other languages, I mean I've worked on C# and Python code bases where the linter was configured to not allow functions with to much complexity (multiple metrics used). The thing is, this is only possible if you work on a code base with a fixed toolchain like a linter. It's great for things like C# or Python where there is one coherent ecosystem. Thats not the case in the C world, where you have dozens of different compilers, linkers, editors, etc. Also for Pascal AFAIK theres also no Pascal Linter that assesses code complexity. So thats why you don't see that strict enforcement in other languages, because they have other tools for that.

Also note, I personally find these linters even worse. Because now you rely on hard metrics encoded in the linter rules, while if you structure your code in a way that makes it easily assessable by eye, you have more felxibility. Some functions need to be complex, so exceptions to the rule are always possible. You can't argue with a linter
« Last Edit: October 03, 2024, 04:42:51 pm by Warfley »

Ryan J

  • Full Member
  • ***
  • Posts: 138
Re: Making a plea :)
« Reply #34 on: October 03, 2024, 04:44:10 pm »
Where are the features that are needed deep inside a framework, and really enable whole new concepts and code in an application wide matter? Other than a few remarks of Warfley (wrt to generics and STL) I haven't heard much.

What features are these? I see lots of good feature requests and ergonomic matter if you ask me. It doesn't matter how "correct" your paradigm is, if it makes people annoyed to use they will go elsewhere and the language dies.

Thaddy

  • Hero Member
  • *****
  • Posts: 16177
  • Censorship about opinions does not belong here.
Re: Making a plea :)
« Reply #35 on: October 03, 2024, 04:47:00 pm »
I will name a couple of those that Warfley referred to regarding the Linux kernel code:
1. readability and maintainability
2. consistency in coding style
3. inlined vars can lead to stack misalignment. If the var is declared up front the compiler can better optimize. (you should know that Ryan!)
4. inlined vars are error prone. (Usually, they are forbidden anyway in big shops.)
« Last Edit: October 03, 2024, 04:49:02 pm by Thaddy »
If I smell bad code it usually is bad code and that includes my own code.

Ryan J

  • Full Member
  • ***
  • Posts: 138
Re: Making a plea :)
« Reply #36 on: October 03, 2024, 04:49:02 pm »

It seems to me that you don't want actual variables here, but defines:
Code: Pascal  [Select][+][-]
  1. {$define x:=long expression1}
  2. {$define y:=long expression2}
  3. fun(x, y);

No need to add any new featrue to the compiler for this


He wants some scratch memory for a temporary variable basically. If he has to declare them now his scratch memory is part of the function scope even though it's used in one area. Name pollution is a problem now too. Pulling it out into another function is annoying  also and un-inlines code making it potentially  harder to understand.

Defines are a silly idea here. Those are now global scope and you lose type checking.

Ryan J

  • Full Member
  • ***
  • Posts: 138
Re: Making a plea :)
« Reply #37 on: October 03, 2024, 04:53:29 pm »
3. inlined vars can lead to stack misalignment. If the var is declared up front the compiler can better optimize. (you should know that Ryan!)
4. inlined vars are error prone. (Usually, they are forbidden anyway in big shops.)

First points seem like a personal preference so I won't address them.

3. No I don't know that. :) I thought inline vars were always declared at the top during code generation. What even is a misaligned stack?

4. How? The only problem I can think of is overlapping names but you can do this in Pascal with implicit self and parameters anyways.

Warfley

  • Hero Member
  • *****
  • Posts: 1758
Re: Making a plea :)
« Reply #38 on: October 03, 2024, 04:55:32 pm »
Defines are a silly idea here. Those are now global scope and you lose type checking.
Solution to globality:
Code: Pascal  [Select][+][-]
  1. {$define x:=expr}
  2. // use x
  3. {$undef x}
And of course you have typechecking, at the time of use it's type checked. It's for the usecase outlined in the text even better than a variable, because it does not cause unecessary moves between memory locations, and no implicit typecasting when being put into a typed variable (e.g. if the variable is of type Integer and the function takes Double, you have an implicit conversion in there).  Meaning you get better typechecking if you use defines, as it then checks against the type of the function parameter, not the type of the variable.

Especially, as I said previously already, type inference in FPC can give a real headache (as it always assumes smaller int types, but for some reason always the largest float type)

marcov

  • Administrator
  • Hero Member
  • *
  • Posts: 11941
  • FPC developer.
Re: Making a plea :)
« Reply #39 on: October 03, 2024, 05:02:08 pm »
Where are the features that are needed deep inside a framework, and really enable whole new concepts and code in an application wide matter? Other than a few remarks of Warfley (wrt to generics and STL) I haven't heard much.

What features are these?

They are rare. Because a good case must be made for them rather than opinion and pointing to other languages :-0

It is also perfectly fine not to be extending the language.  Not all programming problems need to be solved with language extensions

Quote
I see lots of good feature requests and ergonomic matter if you ask me.

I know you have been submitting copy-this-and-that-feature requests for near on a decade, so your opinion doesn't surprise me.

Quote
It doesn't matter how "correct" your paradigm is, if it makes people annoyed to use they will go elsewhere and the language dies.

As long as that is outweighed by people coming here because the language is so clean  :)

Seriously, usually the criterium is what you can do with a development system (which is in itself language, libraries, IDE and language implementation, read: compiler). Not exchanging micro language syntax bullet lists on reddit.
« Last Edit: October 03, 2024, 05:06:48 pm by marcov »

Ryan J

  • Full Member
  • ***
  • Posts: 138
Re: Making a plea :)
« Reply #40 on: October 03, 2024, 05:03:05 pm »
Defines are a silly idea here. Those are now global scope and you lose type checking.
Solution to globality:
Code: Pascal  [Select][+][-]
  1. {$define x:=expr}
  2. // use x
  3. {$undef x}
And of course you have typechecking, at the time of use it's type checked. It's for the usecase outlined in the text even better than a variable, because it does not cause unecessary moves between memory locations, and no implicit typecasting when being put into a typed variable (e.g. if the variable is of type Integer and the function takes Double, you have an implicit conversion in there).  Meaning you get better typechecking if you use defines, as it then checks against the type of the function parameter, not the type of the variable.

Especially, as I said previously already, type inference in FPC can give a real headache (as it always assumes smaller int types, but for some reason always the largest float type)

Not following this 100%. If you break up an expression into 2 variables and copy the text into a define how do you get type checking? If this is so good why not put all your variables in defines. Not sure about FPC but I think most compilers are really good at eliminating temporary variables used to make code easier to reason about.

440bx

  • Hero Member
  • *****
  • Posts: 4735
Re: Making a plea :)
« Reply #41 on: October 03, 2024, 05:14:49 pm »
Actually assuming anything on the lifetime of the inline variables, is yet another feature layer on top of that.
The language has to provide mechanisms to clearly set the scope's beginning and end which determines the lifetime of the inline variables.  In the case of Delphi, it is "begin" and "end" (which I personally consider very poor scope delimiters.)  In the case of C, the "{" and "}" braces (as equally deficient as "begin"/"end" in Pascal - Delphi should improve instead of just copy other language's poorly implemented features.)

In any case, nothing special about it.

Note: I missed your response, that's why this post is a bit on the late side.

(FPC v3.0.4 and Lazarus 1.8.2) or (FPC v3.2.2 and Lazarus v3.2) on Windows 7 SP1 64bit.

Ryan J

  • Full Member
  • ***
  • Posts: 138
Re: Making a plea :)
« Reply #42 on: October 03, 2024, 05:15:58 pm »

I know you have been submitting copy-this-and-that-feature requests for near on a decade, so your opinion doesn't surprise me.


Because I'm trying to learn new things from other languages and address issues in Pascal that are more frustrating when I switch languages.

There seems to be an idea here that Wirth figured out everything there is to know about programming in 1980 and everything has been downhill since. This is surprising because the primary driver of new features in FPC seems to be copying Delphi. I can understand why you'd want to preserve the legacy of something historical but FPC is already way off the deep end with OOP, interfaces, generics, nested functions, dynamic arrays and everything else that was added (most for Delphi compatibility as the primary driver it appears to me).

Warfley

  • Hero Member
  • *****
  • Posts: 1758
Re: Making a plea :)
« Reply #43 on: October 03, 2024, 05:27:57 pm »
Not following this 100%. If you break up an expression into 2 variables and copy the text into a define how do you get type checking? If this is so good why not put all your variables in defines. Not sure about FPC but I think most compilers are really good at eliminating temporary variables used to make code easier to reason about.
I've understood the original point such as that they did not want to write large expressions into the function call, but rather have them for readability defined elsewhere.

Of course then the solution should be to have a construct that allows defining a compiletime expression that will be substituted, rather than introducing a runtime variable which involves memory copies and stuff like that

MarkMLl

  • Hero Member
  • *****
  • Posts: 8029
Re: Making a plea :)
« Reply #44 on: October 03, 2024, 05:32:17 pm »
There seems to be an idea here that Wirth figured out everything there is to know about programming in 1980 and everything has been downhill since. This is surprising because the primary driver of new features in FPC seems to be copying Delphi. I can understand why you'd want to preserve the legacy of something historical but FPC is already way off the deep end with OOP, interfaces, generics, nested functions, dynamic arrays and everything else that was added (most for Delphi compatibility as the primary driver it appears to me).

Yes, that is a valid point but by that time Pascal had already been in use for ten years.

MarkMLl
MT+86 & Turbo Pascal v1 on CCP/M-86, multitasking with LAN & graphics in 128Kb.
Logitech, TopSpeed & FTL Modula-2 on bare metal (Z80, '286 protected mode).
Pet hate: people who boast about the size and sophistication of their computer.
GitHub repositories: https://github.com/MarkMLl?tab=repositories

 

TinyPortal © 2005-2018