if (RadioButton.Checked) then
Exit;
Invert the condition and use one more begin-end pair:
case I of somevalue : begin statement ... statement... if not someconditionhere then begin // the opossite condition statement ... statement.... end; end; <more cases here> end; { case }
Or you can put a label under end {case} and use goto.
Again, there is no need for break in Pascal case of clause statements. If one statement is true, the rest are ignored.Cyrax, yes, that is a fact. The point is to break out early as the example I posted showed.
Again, there is no need for break in Pascal case of clause statements. If one statement is true, the rest are ignored.Cyrax, yes, that is a fact. The point is to break out early as the example I posted showed.
It's unfortunate there is no way of exiting a case block early. An if statement solves the problem but, if there are multiple conditions which would cause the case to break early then that would result in the nesting of multiple if statements to implement what is really very simple, linear not hierarchical, logic.
In this simple example inverting the condition is probably the best solution but if you find yourself in a situation in which "there are multiple conditions which would cause the case to break early" I would suggest moving the body of that selection to a separate function or procedure where you can use Exit to your heart's content :) :Absolutely, that's one solution and it is reasonable. That said, any solution that requires a form of nesting is not as clean and simple as a solution that is fully linear which is what being able to break out early of a case would enable.
emulate it.In this simple example inverting the condition is probably the best solution but if you find yourself in a situation in which "there are multiple conditions which would cause the case to break early" I would suggest moving the body of that selection to a separate function or procedure where you can use Exit to your heart's content :) :Absolutely, that's one solution and it is reasonable. That said, any solution that requires a form of nesting is not as clean and simple as a solution that is fully linear which is what being able to break out early of a case would enable.
Unfortunately, the answer to my question is: there is currently no way to break out early of a case statement.
I'll keep that in mind when porting C code to Pascal. The resulting code will not be as simple as in C (which is unusual, usually Pascal code is cleaner than C.)
emulate it.
Why not put the code of that case into a procedure?
No, the choices presented here are as easy and straight forward as a call to break. I see no reason to change break.emulate it.Why not put the code of that case into a procedure?
Absolutely. Those are both reasonable workarounds. There is no shortage of ways to implement the logic. It's just unfortunate that the simplest and cleanest solution, which is to break out of the case, simply isn't available. Oh well...
Thank you for the suggestions, I appreciate them.
Allowing "break" in a case statement would be a nice addition to the language and, best of all, it isn't hard to implement. May be a feature the developers might be willing to consider.
No, the choices presented here are as easy and straight forward as a call to break. I see no reason to change break.Those choices are easy and straightforward but, they break linear flow. Those choices could be used in any loop too. Following your logic, there is no need for "break" in a loop either.
true break is just a familiar construct nothing more.No, the choices presented here are as easy and straight forward as a call to break. I see no reason to change break.Those choices are easy and straightforward but, they break linear flow. Those choices could be used in any loop too. Following your logic, there is no need for "break" in a loop either.
It's about controlling logical flow. Not having to nest into ifs or call function/procedures when a linear solution is possible.there are proper flow control constructs no need to extend a hack to a flow control construct.
At this point, it looks like we should probably agree to disagree.on all accounts I guess.
Bottom line is simple: there is no way in Pascal to break out early of a case statement. When that is needed, which is quite common, C provides a better, simpler, cleaner solution.There are. you simple choose to reject them.
I think using break inside a case would break some code that was supposed to exit the loop:Now, that is a reasonable objection and, your example shows that it is, at least somewhat likely, that it would. That's unfortunate since it is a good reason not to implement break in case statements.
while somecondition do case I of val1: if shouldLeaveLoop then Break val2: .... end;
Allowing "break" in a case statement would be a nice addition to the language and, best of all, it isn't hard to implement. May be a feature the developers might be willing to consider.
What did you think of using Repeat/Until in place of Begin/End, which would facilitate Break?I like it. It's a nice trick to implement a scope that can be broken out of. Sort of a begin/end pair that can be broken out of. Can be very handy, Of course, it needs to be commented as to its real purpose so the programmer who sees it knows why it's being done.
I'm agreed with Thaddy (not always :D).There is a big difference between break and a goto. The destination of a break is preset by where it occurs. A goto can go anywhere. Break and goto do the same thing only for people who are better at babbling than programming.
You said you don't want to use goto, but break is doing the same.
Break and goto do the same thing only for people who are better at babbling than programming.
One could almost say that they were created to allow you to sneak a "goto" while avoiding that culpable feeling that real gotos produce :)No. They were created because they solve the inherent problem of the goto statement, which is that the destination is, unlike with break, continue, etc, not predetermined.
Actually you are a bit incomplete in your explanation: those goto's are assembler jumps generated by the compiler. As such they have little to do with an actual high level language construct.Break and goto do the same thing only for people who are better at babbling than programming.
You're wrong, you know. Break, Continue, Exit, etc. are just specialized Gotos; the fact that their destination is preselected doesn't negate this.
One could almost say that they were created to allow you to sneak a "goto" while avoiding that culpable feeling that real gotos produce :)
Actually you are a bit incomplete in your explanation: those goto's are assembler jumps generated by the compiler. As such they have little to do with an actual high level language construct.The two of you should get a room, share your gotos.
But your answer is more correct than that babbler. 8-)
The two of you should get a room, share your gotos.
unless the programmer specifically specifies a fall-through case with 'also', no fall-through will occur. The keyword 'done' is used to leave the 'when' block. It adds a total of three keywords to control a switch in SharpBASIC: 'also', 'done' and 'other'. Best of all: it works!
var n: int = 0; when n is 0 do n = 1; is 10 do n = 0; also is 1 do ' "fall-through" n = 2; done; ' leave 'when' block also is 2 do ' "fall-through" n = 3; is other do n = -1; end; print n; ' 2
The "done" thing (if it is like the break 440bx wanted) is nice, and "is Other" is equivalent to "else" and "otherwise" in Pascal, isn't it? But that "also" ... I mean, that:looks a tiny absurd: when "n" is 10, it can't be 1, can it? So, what is it supposed to do?
is 10 do n = 0; also is 1 do ' "fall-through"
Granted, you go about changing "n" and that might have some bearing with it but it looks a litle confussing (at least to me).
The "done" thing (if it is like the break 440bx wanted) is nice, and "is Other" is equivalent to "else" and "otherwise" in Pascal, isn't it?
<...> unless the programmer specifically specifies a fall-through case with 'also', no fall-through will occur.That's the way to do it. C making the fall-through the default is yet another design atrocity in that language.
So it is not really a "fall through" but more like a "test again" if the programmer specifies a 'also is' test.
I'd rather have the fall-through made explicit instead of implicit by the use of a keyword ("also") that doesn't clearly denote it is meant to fall through.
Also (pun intended), do you really need the "is" ?
Also (again!) one advantage I see to having an explicit "fall" is that the "fall" can then be made conditional
So it is not really a "fall through" but more like a "test again" if the programmer specifies a 'also is' test.
I think I got it, but just to test my understanding: the equivalent in (current) Pascal would then be someting like,Is that right?
case n of 0: n = 1; 10: begin n = 0; case n of 1: n = 2; 2: n = 3; end; end; else n = -1; end;
EDIT: 'done' has been replaced by 'leave'.I like "leave" better. I think it makes the intention clearer.
I know the discussion is about breaking out of a case statement, but it got my mind spinning. What about a case expression, like this:
function Fibonacci(n: Integer): Integer; begin Result := case n of <1. : 0; 1, 2: 1; else Fibonacci(n-1) + Fibonacci(n-2); end;
'else' should be mandatory, to determine the end of the expression.
Sorry for the off-topic...
Am I correct in assuming that if fall-through is not the default like in C, a break / leave statement is not necessary?
when n is 0 do n = 1; fall; is 1 do n = 2; is 2 do n = 3; is 3 do n = 4; end;
But allowing to change the case condition and then fall through is messy IMHO.I agree. That wouldn't be an option.
I would leave out fallthrough entirely. Not worth the effort, mostly theoretical cases only.
fall through _is_ the default in C, which can be a very annoying characteristic.
fall through _is_ the default in C, which can be a very annoying characteristic.
I would leave out fallthrough entirely. Not worth the effort, mostly theoretical cases only.I disagree here. We used to use that a lot in C libraries where some of the options needed preparatory setup before any option later in the switch could be executed, example: partial information need to be completed first. E.g. when a ticker was not yet in the cache, so its static information needed to be retrieved first before processing trade information.
How is all that code / discussion related to freepascal / object pascal ?It has been a feature request more than once.
The first is inefficient, the second can written better with sets.Ok for the first, except it addresses breaking out early.
Yes, like Thaddy said, a loop is inefficient. It requires a conditional jump and a full case walk-over each time, whereas a fall instruction is just one unconditional jump. I addition, each fall can be made conditional:Please, can you comment what this bit of code is supposed to do or where documentation can be found on such instructions.
var n: int = 0; main do when true is 1 > n do when n is 0 do n = 1; if n > 0 do fall; end; is 1 do n = 2; end; end; end;
Please, can you comment what this bit of code is supposed to do or where documentation can be found on such instructions.
Just explain what this line means please.
when true is 1 > n do
While n < 1 do.IF
Rpn
That looks good.
var n: int = 0; main do when n is 0 do n = 1; fall; is 1 do n = 2; fall; is 2 do n = 3; fall; is 3 do n = 4; end; print n; ' 4 end;
I thank everyone here on the FP forum for their input and ideas.And thank you for implementing ideas that are mostly the removal of a wrinkle/deficiency in an existing concept that has proven useful.
years of experience with FBC and FPC and could be considered sort of an amalgamation of the two.Curious... what programming language are you using to write the SharpBasic compiler ?
Reading the history of FPC again and its struggles to be TP and Delphi compatible, after some 5 months effectively working on the SharpBASIC compiler (SBC), I realize how constraining it must be to model a new compiler after an existing language
Honestly, I admire the FPC and also FBC (FreeBASIC) developers for honouring the restrictions/limitations and also the ambiguities of the original language for maximum compatibility. It certainly wouldn't be my cup of tea! I say this as a frequent FPC and FBC user; even a trivial thing such as declaring and initializing multiple variables can be hard/impossible to implement:
Well, if you phrase it as "struggles", the mind seems to be already made up before you get to the end of the sentence :-)Wikipedia:
The principal problems were that adding processors meant rewriting the code generator, and that the register allocation was based on the principle of always keeping three free registers between building blocks, which was inflexible and difficult to maintain.
For these reasons, the 1.1.x series branched off from the 1.0.x main branch in December 1999. At first, changes were mostly clean-ups and rewrite-redesigns to all parts of the compiler. The code generator and register allocator were also rewritten. Any remaining missing Delphi compatibility was added.
I think it is more a difference in goals. Making a widely used suitable for production compiler is simply hard and iterative. There is also a significant difference in general between a one person team, and a multi person team. With multiple people there are also multiple opinions, directions etc.I agree that it is a long way to a compiler successfully targeting multiple platforms. If I read correctly, initial development of the FPC compiler 1993-1995 was also done by one person and the compiler took off after Florian Klämpfl released it. A firm codebase is essential, otherwise, with different opinions, a compiler may actually never be born.
QuoteHonestly, I admire the FPC and also FBC (FreeBASIC) developers for honouring the restrictions/limitations and also the ambiguities of the original language for maximum compatibility. It certainly wouldn't be my cup of tea! I say this as a frequent FPC and FBC user; even a trivial thing such as declaring and initializing multiple variables can be hard/impossible to implement:
If such micro syntax is the biggest problem in a language, you'd be very happy. Keep in mind that the Pascal parsing model was ingrained into the fabric of the project. Foreign constructs not matching the model might not have been considered a small or even negligible sacrifice.
Anyway don't fall for the micro syntax trap, it takes more to make a good language than simply implementing a superset of all shorthands of all languages.
In the end what attracts users is visible ability/proof to complete certain tasks, like sizeable programs in the project's target domain. It is not simply a matter of bullet lists of micro syntax comparisons.Agreed.
years of experience with FBC and FPC and could be considered sort of an amalgamation of the two.Curious... what programming language are you using to write the SharpBasic compiler ?
The other question I have is, do you have plans to making it opensource ?
sub _sb_copystr(p_src: ptr, p_dest: ptr, length: uint)
do
asm do
push esi
push edi
push eax
push ecx
mov esi, [ebp + 16] ; source
mov edi, [ebp + 12] ; destination
mov ecx, [ebp + 8] ; length
cmp ecx, 0 ; larger than 0 ?
jle .out
.copy:
mov al,[esi] ; from source
mov [edi],al ; to destination
inc esi ; increment pointers
inc edi
dec ecx ; decrement counter
cmp ecx, 0 ; done?
jne .copy
.out:
pop ecx
pop eax
pop edi
pop esi
end;
end;
Well, if you phrase it as "struggles", the mind seems to be already made up before you get to the end of the sentence :-)Wikipedia:QuoteThe principal problems were that adding processors meant rewriting the code generator, and that the register allocation was based on the principle of always keeping three free registers between building blocks, which was inflexible and difficult to maintain.
For these reasons, the 1.1.x series branched off from the 1.0.x main branch in December 1999. At first, changes were mostly clean-ups and rewrite-redesigns to all parts of the compiler. The code generator and register allocator were also rewritten. Any remaining missing Delphi compatibility was added.
I agree that it is a long way to a compiler successfully targeting multiple platforms. If I read correctly, initial development of the FPC compiler 1993-1995 was also done by one person and the compiler took off after Florian Klämpfl released it. A firm codebase is essential, otherwise, with different opinions, a compiler may actually never be born.
This is not about deliberate micro-syntax (although less verbosity might be a goal), but rather about flexibility.
I've seen feature request both for FPC and FBC that appear difficult to implement because of the compiler's design. When starting development of a new compiler, implementing such features right at the start is much easier. SBC is not the first project started due to a new language design wish.
Agreed.
So what domain do you think Sharpbasic will excel in? What is the big picture?I haven't given it too much thought yet. The first goal is a stable compiler that generates at least 32 and 64 bit programs for Linux and Windows (GUI bindings might be added at that point). Possibly, programmers that see a use for the compiler on other architectures might want to add the specific code generation to the compiler. There's also the question of OOP with classes or only interfaces as Go has. But SBC will certainly support structures/types (NASM supports them natively). Right now I'm working on strings, then arrays, then types, all needed to make the compiler self-hosting.
Anyway don't fall for the micro syntax trap, it takes more to make a good language than simply implementing a superset of all shorthands of all languages.But, in a way, it is. Designing a language and writing a compiler for it are no simple tasks and, it is not realistic to think that its design and implementation will be perfect the first go round. Like most everything, getting to something that is a real pleasure to use is an iterative process consisting of a long string of mostly small improvements - what you deride as "micro-syntax".
In the end what attracts users is visible ability/proof to complete certain tasks, like sizeable programs in the project's target domain. It is not simply a matter of bullet lists of micro syntax comparisons.
In the end what attracts users ... is not simply a matter of bullet lists of micro syntax comparisons.But, in a way, it is.
With regret, I join this thread to say I agree. You only have to look at the popular distinction between "curly bracket languages" and "Everything else".
#include <gtk/gtkaboutdialog.h>
#include <gtk/gtkaccelgroup.h>
#include <gtk/gtkaccessible.h>
#include <gtk/gtkactionable.h>
... (some 250 includes in gtk.h only)
incl is
"gtk/gtkaboutdialog.h";
"gtk/gtkaccelgroup.h";
"gtk/gtkaccessible.h";
"gtk/gtkactionable.h";
...
end;
These languages are way too symbolic for my taste.
Getting to something that is a real pleasure to use is an iterative process consisting of a long string of mostly small improvements - what you deride as "micro-syntax".
Being consistently against small improvements that add polish to a compiler/grammar, which I'm afraid, you tend to be, only yields a result that is not well polished around the edges.
That is a matter of taste. If you value detail syntax over real features, it might seem that way. But that is not an universal truth.
Missing 'detailed features' adds to little annoyances over time. If there's room/logic to implement them, then why not? Taking grouped initialization as example, I remember having to set several iterators/counters to zero statement by statement after declaration, which is probably the first reason for the grouped initialization feature request.
That is a matter of taste. If you value detail syntax over real features, it might seem that way. But that is not an universal truth.
Detailed syntax is not an antithesis to real features.
Missing 'detailed features' adds to little annoyances over time.
If there's room/logic to implement them, then why not?
Taking grouped initialization as example,
I remember having to set several iterators/counters to zero statement by statement after declaration, which is probably the first reason for the grouped initialization feature request.
Admittedly, it doesn't carry as much weight as 'real features', but that's no reason to ignore those 'detailed features'. Polishing a compiler just adds that little extra that allows for an ever better programming experience.
Earlier in this thread you also opted for leaving out explicit fall through, which I would say is more than a detailed feature.
Only in the eyes of people that want to see any missing shorthand from any other language as such. As said they are more about giving a false sense of familiarity than about productivity.
a := if b then c else d;
Code: [Select]a := if b then c else d;
However as a counterexample I'd like to highlight the ALGOL-style conditional expression that Wirth unaccountably omitted from Pascal:Code: [Select]a := if b then c else d;
since this can't easily be emulated using a function and is such a common idiom in mainstream ALGOL derivatives- by which I of course mean C etc.- that its absence is embarrassing.
a := math.ifthen (b,c,d);
Hasn't there has been talk about this, ifthen() becoming an intrinsic and only evaluating the sides as necessary. (because objective pascal needed it???)
I don't know if it happened in the end. Maybe Pascaldragon knows.
I don't believe that any occasional verbosity automatically warrants a language expansion. Moreover because FPC is not a language experimentation project in the first place.The multiple initialization feature isn't about eliminating some verbosity. It is about giving the language a mechanism that allows it to show that 2 or more variables should have the same initial state.
function iif(a: Boolean; b, c: Variant): Variant; inline; begin if a then Result := b else Result := c; end;
Or use generics, if you don't want the conversions.
I don't believe that any occasional verbosity automatically warrants a language expansion. Moreover because FPC is not a language experimentation project in the first place.The multiple initialization feature isn't about eliminating some verbosity. It is about giving the language a mechanism that allows it to show that 2 or more variables should have the same initial state.
This would be error prone if each variable had to be declared individually and, it would make maintenance more difficult.
For those same reasons, the language should support multiple variable initialization. I believe you know this but, instead you pretend it's about "verbosity" and FPC not being an "experimentation project".
As I've said twice already, that doesn't work because when called all parameters are evaluated (with potential side-effects) before the condition is evaluated. I'm sorry, but this one really is an old chestnut.
I don't know- and am not going to investigate- whether ALGOL W had this form of conditional. If for some reason it didn't then it might explain why it didn't get into Pascal.
I'm actually here and investing the time to discuss with you. Please respect that.I respect that but...
Please explain this in more detail. What are concrete practical benefits of doing this, other than for some fuzzy feeling of orthogonality/symmetry for the grammar police? What checks or features do you envision on top of this?The answer to your concerns is very simple and, it is shown quite well by the fact that the language allows defining a group of variables of the same type. i.e,
More syntactical features also make a language harder to read, and thus increase failure rate, specially for rarely used constructs like this. So I would wager it is is a net loss.
In addition to that, the missing multiple variable initialization shows there is an inconsistency in the grammar and that the grammar is gratuitously intransitive where it could easily be. Specifically,I second that. In the case of Pascal, it is either because of language compatibility issues (the compiler modeled after an existing language), or it is a compiler design flaw. I don't think that targeting multiple architectures would make it more/too difficult to support such basic feature. I remember QuickBASIC had some limitations with declaring variables, simply because the developers didn't think of it or they felt it was not significant enough to them to implement. But that's talking of a 1980s compiler.but, when you try
var VariableA : integer = 0; { no problem initializing this } VariableB, VariableC, VariableD : integer; { no problem with that either - and it _not_ about eliminating verbosity }A language that allows the first two, should also allow the third simply for symmetry, consistency and completeness (of course, why would anyone care about those things.)
VariableB, VariableC, VariableD : integer = 0; { sorry, no can do }
Keep in mind that in those days there were years between language definition and implementation. (68-70 in Pascal's case)
Wirth notoriously liked orthogonal and simple grammars. Like 440bx but in a more subtractive than additive way.
I think the feature simply didn't make the cut to be considered "base algol subset".
Keep in mind that in those days there were years between language definition and implementation. (68-70 in Pascal's case)
No, actually local variables of a function/procedure are not zeroed. Members of a class are zeroed.
procedure Bla; var i:Integer; begin i := 0; .. end;
In the above code, initializing i to 0 is superfluous, as all variables are zeroed by default. The same goes for the function result. But it makes it much more readable.
procedure Bla; var i:Integer; begin i := 0; .. end;
In the above code, initializing i to 0 is superfluous, as all variables are zeroed by default. The same goes for the function result. But it makes it much more readable.
No, actually local variables of a function/procedure are not zeroed. Members of a class are zeroed.
With that mechanism the language ensures that 2 or more variables that must be of the same type are declared in a group all having the same type. If that feature wasn't there and 2 or more variables had to be of same type then, ensuring they are of the same type would require the programmer to inspect every variable declaration to ensure they are of the same type and, if during maintenance, a programmer changes the type of one variable, it would not be obvious that the types of the other variables also has to be changed. That is a problem.
No, actually local variables of a function/procedure are not zeroed. Members of a class are zeroed.
No, actually local variables of a function/procedure are not zeroed. Members of a class are zeroed.
Aren't managed variables like strings initialised to guaranteed minimum length as well?
Wirth notoriously liked orthogonal and simple grammars. Like 440bx but in a more subtractive than additive way.
How can that statement possibly be reconciled with the const, type and var divisions, which could easily have been wrapped in some sort of block structure?
The bulk of the work was done between May and October 1969, but the details were still fairly fluid in '70.
The problem is that Wirth was still using recursive ascent which was notoriously difficult to maintain... have you looked at the source of his early compilers?
Unless of course it was a casualty of e.g. an attempted fix of e.g. the dangling else issue, which he'd had to walk back in a hurry when he hit his time constraints.
Aren't managed variables like strings initialised to guaranteed minimum length as well?
Afaik that is considered an implementation detail, and to keep compatible with shortstrings, it was advised not to abuse that, so that string code could be swapped betwixt them.
**(*((*SomeIdentifier)*)*)
and asked why those fields had to be explicitly initialised if their state was known.To make it easier to understand?
MarkMLl
And I doubt you can truly understand C++. Too much special cases and most of what you can do, you really shouldn't.
Which perfectly demonstrates that allowing one shorthand only needs to the next.That reply of yours is an excellent example of your tendency to present useful features as if they were programming platitudes.
Being able to specify a group of variables to be of the same type by making it a single declaration is hardly a simple shorthand.
var a,b: integer;
var a: integer;
b: integer;
The "group of variables" only exists to justify the need for the initialization shorthand. It isn't a real thing.
What is the concrete difference betweenThe concrete difference between those two is that, if used properly, the first construct informs the programmer that the two variables in the declaration should be of the same type.
var a,b: integer;
vs
var a: integer; b: integer;
?
Who would prefer the second syntax if the first were available?Not to mention that there is no good reason not to have the first option. It's the natural option.
The "group of variables" is basically what is discussed in the FP Reference Guide, section 3.5, where it explicitly says
The referenced type should be introduced later in the same Type block. No other block may come between the definition of the pointer type and the referenced type.
So there's already strong precedent for considering types or variables declared together being in some way related to a greater extent than if they'd been declared separately. I believe that that was subsequently tightened up in Modula-2.
var a, b, c: integer = 0; s1, s2: string; begin //.. end;
Modula2 also added "opague" forward references, which were looser,
Who would prefer the second syntax if the first were available?Not to mention that there is no good reason not to have the first option. It's the natural option.
I would not be in favor of that one because transpositions are a common error. That construction makes it too easy to inadvertently swap initial values.
var a, b, c: integer = (0, 0, 0); s1, s2: string; begin //.. end;
I remember having this discussion before and if memory serves me well, the grouped initialization syntax cannot be easily implemented in FPC. While I haven't looked at the FPC source myself, I can imagine that if the parser feeds the syntax directly to a AST structure, the initialization may be a problem.Yes, I remember that too. From memory and, if I understood what was said at the time, apparently there is some code that is shared with other portions of the compiler that would not welcome the minor changes required in parsing an initial value.
SharpBASIC doesn't do it like that. It collects all declarations with type and initialization (immediate) and adds them to the symbol table. After the stack frame is setup the symbol table (with initializations) is read out and the variables are initialized.That's the best way of doing it. Much more powerful and flexible.
The concrete difference between those two is that, if used properly, the first construct informs the programmer that the two variables in the declaration should be of the same type.
What's next, reviewing of all block structures to omit vowels other than "e" and "i",
But whatever the reason is, that kind of undocumented intent is IMHO a very shaky ground to build some grand consistency argument on top of.Undocumented ?... it seems to me that one of the things programmers have to learn early in the process of learning to program is to group things that belong together (like declarations and sequences of code) and keeping separate, things that don't belong together (which usually goes by the more academically polished word "modularization".)
I have not seen any programming manuals document that the reader has to have the ability of recognizing individual glyphs, grouping them, associating a semantic meaning to specific groups in order to be able to read the fine manual.
Should I open a bug against the FPC documentation to have this undocumented requirement be brought to light ?You most definitively must!
Should I open a bug against the FPC documentation to have this undocumented requirement be brought to light ?You most definitively must!
What's next, reviewing of all block structures to omit vowels other than "e" and "i", because those are the ones that are in begin and end, for consistency's sake ?
I have not seen any programming manuals document that the reader has to have the ability of recognizing individual glyphs, grouping them, associating a semantic meaning to specific groups in order to be able to read the fine manual. Should I open a bug against the FPC documentation to have this undocumented requirement be brought to light ?
However as a counterexample I'd like to highlight the ALGOL-style conditional expression that Wirth unaccountably omitted from Pascal:Code: [Select]a := if b then c else d;
since this can't easily be emulated using a function and is such a common idiom in mainstream ALGOL derivatives- by which I of course mean C etc.- that its absence is embarrassing.
Hasn't there has been talk about this, ifthen() becoming an intrinsic and only evaluating the sides as necessary. (because objective pascal needed it???)
I don't know if it happened in the end. Maybe Pascaldragon knows.
I had added it back in January 2016 (see announcement mail (https://lists.freepascal.org/pipermail/fpc-pascal/2016-January/046376.html) of which the thread continued into February (https://lists.freepascal.org/pipermail/fpc-pascal/2016-February/046385.html)). After some heated discussions both on the public mailing list as well as the core one I removed it again in February (https://lists.freepascal.org/pipermail/fpc-pascal/2016-February/046617.html). The addition of the intrinsic is still part of the version history (https://gitlab.com/freepascal.org/fpc/source/-/commit/ed94ca4b24c3eb979383ae4f846da4047b70ac00) and I think somewhere I still have a patch for the if … then … else - expression (alternatively it would be easily derivable from the provided commit for the IfThen intrinsic).
fn main() { let condition = true; let number = if condition { 5 } else { 6 }; println!("The value of number is: {}", number); }
MarkMLl
In my opinion this code is messy because the keywords IF and ELSE in such languages are both statements and operators. The syntax is trivial at best because it can be written in statements with the same effort and same amount of code. The only benefit is that the code is crammed on a single line. What benefit is that? There's absolutely no need here to make things more complicated for the compiler. A wise decision that Pascal didn't adopt it.
In my opinion this code is messy because the keywords IF and ELSE in such languages are both statements and operators. The syntax is trivial at best because it can be written in statements with the same effort and same amount of code. The only benefit is that the code is crammed on a single line. What benefit is that? There's absolutely no need here to make things more complicated for the compiler. A wise decision that Pascal didn't adopt it.
I'll leave you to argue that with the Rust community, and with the ALGOL-60 designers before them. I'm done with arguing.
MarkMLl
But that's my personal opinion.I really like the python version:
fn main() { let condition = true; let number = if condition { 5 } else { 6 }; println!("The value of number is: {}", number); }
MarkMLl
Actually, discussions like these can be inspiring. I might just think of supporting a similar shorthand for the compiler I'm working on. But it should be clear and different from other statements, perhaps something like:Personally, just from looking at it, I think this solution isn't very great, because if I didn't have the context on what it is supposed to mean, I wouldn't understand it. Languages should be expressive on their own, reading a program should be as easy as possible.
by condition { number = 5, 6 };
The benefit of such construct is that due to a different keyword (by) it could be processed separately and never reach the expression parser. Just a spontaneous idea.
I don't like flame wars, and from my POV the core team has made their position clear. But it still rankles that a fundamental element that apparently gave ALGOL no problems was omitted from Pascal.
I also don't like C-style usage of ? since it breaks the otherwise-close correspondence between operators and procedure/function invocation, which in all cases evaluate parameters before applying the operation.
I really like the python version:
myvar = 6 if condition else 7
Also I think it would be really cluttered if it was chained
An initial keyword (in this case if) makes it much easier for the parser to handle
I don't like that order as it would require annoying changes in the parser. An initial keyword (in this case if) makes it much easier for the parser to handle (which is also why I'd prefer something like lambda x as x * 2 instead of Oxygene's x => x * 2 for a shorter lambda expression syntax and also why I prefer FPC's specialize keyword).Completely understandable, but I would still argue that the value then condition structure is better readable, so this could be done with an initial keyword. Just from the top of my head, something like:
This looks really good, but i would replace "is" with "be" as this sounds much more natural when reading
let number by condition is 5 else 6; end;
or chained:
let number by condition1 is 5 else 6; by condition2 is x else y; // ... end;
Food for thought...
The "not evaluating both branches" is one of the main uses when I use that ternary operator in C(++). It was also the base idea behind the IfThen() intrinsic and would also be the applied to the if … then … else … - expression.
I myself am still a fan of the if … then … else … - expression...
This looks really good, but i would replace "is" with "be" as this sounds much more natural when reading
let number by condition is 5 else 6; end;
or chained:
let number by condition1 is 5 else 6; by condition2 is x else y; // ... end;
Food for thought...
I like this form too. But I think at least if (maybe also then and else) should be changed to something else to avoid confusion and make better distinction between operator and statement.
Making the else clause optional one could do
let color on water == frozen is white; on water == hot is red else blue; end;
Making the else clause optional one could do
let color on water == frozen is white; on water == hot is red else blue; end;
And how would you solve conflicts?
E.g.:
let color on water == frozen is white; on air == hot is red else blue; end;
What would the result be if water is frozen and air is hot?
It may look like a conflict, but it really is a definition switch statement:
let color on water == frozen is white; // exits the let statement if true (no implicit fall-through) on air == hot is red else blue; // if no condition is met color = blue end;
So testing is not on 'water' (the conditions) but on color against any condition. I just meant to demonstrate that if the else clause is optional this let construct can be equal to an if statement.
I think this is confusing. What if we do it like below, what would be value in 'color'?
let color on air == hot is red else blue; // if no condition is met color = blue on water == frozen is white; // exits the let statement if true (no implicit fall-through) end;
I like this form too. But I think at least if (maybe also then and else) should be changed to something else to avoid confusion and make better distinction between operator and statement.
Maybe: when … return … otherwise …
This is also fine: when … then … else …
The point is that the expression is most likely to be introduced due to an Oxygene language mode. And for that it must be if. So why introduce yet another keyword and syntax?
I think this is confusing. What if we do it like below, what would be value in 'color'?
let color on air == hot is red else blue; // if no condition is met color = blue on water == frozen is white; // exits the let statement if true (no implicit fall-through) end;
You were right about the confusion in that in my hastiness I initially gave a bad example with multiple else branches. Of course, the very first else would leave the statement. So when chained/switched, only the last branch should be allowed to include else similar to if.
This is not the place to discuss the design of some other language, but from the POV of my experience with multiple ALGOL-based languages-
With regret, I join this thread to say I agree. You only have to look at the popular distinction between "curly bracket languages" and "Everything else".
MarkMLl
and modern BASIC aspires to that heritage- that syntax... is severely deficient.
I'm also concerned about the consequences if either a Pascal newbie or somebody intent to criticise the language were to read this stuff.
The point is that the expression is most likely to be introduced due to an Oxygene language mode. And for that it must be if. So why introduce yet another keyword and syntax?
Would there also be a mode directive to enable that individually, or would there be too much risk of incompatibility with other syntax?
Going back to the thread where it was withdrawn, I note that a whole lot of the troublesome cases were actually in variable initialisation or function declaration. Allowing that the whole idea is that this generates conditional code and that variable/parameter initialisation/default is by definition resolved at compilation time, is that usage even valid?
Would there also be a mode directive to enable that individually, or would there be too much risk of incompatibility with other syntax?
Yes and there shouldn't be any risk of incompatibility due to if being a keyword recognized by all language modes.
I didn't see that the majority is about variable initialization and function declarations. But no, it wouldn't work there (though in theory one could allow it for constant expressions as well for variable initializations).
Anyway, I should go quiet here since as has been pointed out this isn't "my thread" and I'm responsible for adding noise to it.I guess I am the thread's "owner". For the record, I don't mind at all reading discussions of compiler features and possible implementations. I think it's good for ideas to be publicly discussed and analyzed.
QuoteI didn't see that the majority is about variable initialization and function declarations. But no, it wouldn't work there (though in theory one could allow it for constant expressions as well for variable initializations).
There was something in the postmortem... specifically https://lists.freepascal.org/pipermail/fpc-pascal/2016-February/046626.html
Yeah, I agree with MvC here that this is a very good reason not to allow this as a constant expression at least. :-X Though these would look strange with any other construct as well and in fact currently they'd be done by using $if-constructs which makes them even more ugly... :-\
I take it you mean this?
Type TMyArray = Array[1..if sizeof(integer)=2 then 4 else 5] of integer; myconst = if sizeof(integer)=2 then 4 else 5; Procedure Something(AA : Integer = if sizeof(integer)=2 then 4 else 5); Property A : Integer Index if sizeof(integer)=2 then 4 else 5 read geta; Property B : Integer Read FA Write FA default if sizeof(integer)=2 then 4 else 5 ;
However my principal reason for favouring if-then-else as an expression element is to have Pascal implement as much as possible of ALGOL-60: omissions are embarassing.
MarkMLl
Why? ALGOL-60 was an important development at the time and the language was of major influence to later languages. But it also stems from a time when system resources were very limited. So that the then developers chose to allow the IF-statement in expressions came from necessity rather than elegance. Later language developers were wise to drop the construct. Why that would be embarrassing is beyond me.
However after refactoring a bit of code today where the number of bits needed to represent something was an issue, I find myself wondering whether some other potential cases could be avoided by having something like Log2SizeOf() as an operation which could be resolved at compilation time.
Once we have support for compile time functions (the current term for them is “pure functions”) you can add that yourself ;)
Once we have support for compile time functions (the current term for them is “pure functions”) you can add that yourself ;)
:-) OTOH I'd suggest that that specific case might be worth examining whenever anybody complains that his desired initialisation can't be coded... I'm not suggesting that some implementation be added prematurely, only that it might turn out to be a common "pattern".
No, it's not worth examining, because then the next one will come with the next function and so on. Better focus this into a more general approach.
Also if all you need is the size in bits then you can always use BitSizeOf.
SelectorVariable := 2; { to cause fall through as in C } end; 2 :
the selector was evaluated only at the head of the case statement.Indeed, that's my understanding too, and that's how it works for me in objfpc mode:
You are right, that puzzled me as well because the code of 440bx does work, surprisingly. The trick is in the "while true" loop which repeats the case selection.
You are right, that puzzled me as well because the code of 440bx does work, surprisingly. The trick is in the "while true" loop which repeats the case selection.
The problem is that he's changing the selector, then implying that it falls straight into 2: in the style of C. I agree that wrapping the case in a while works (which is, after all, standard state-machine practice) but I'm very dubious about that claimed fallthrough.
MarkMLl
You didn't understand the point -- in case "1", the selector variable is set to "2", then while loop continues and case "2" is executed in next iteration -- that is emulated fall-through; and that is what 440bx meant, not a real fall-through.
This discussion seems very long :D
I think having a lot of code inside a case statement can get kind of messy. Here is what I would do. I would move the code out of case into procedures.
Case condition of 1:procedure1; 2:procedure2; End;
Procedures are easy to break out of and doing so would make you exit the case statement as well.
The trick is in the "while true" loop which repeats the case selection.Exactly! :)
Mark, there is also something like mode ISO or mode MACPAS that allow non-local goto. Although these modes have several other restrictions, those will exit too depending on how the code is written. On a lower level there is even SetJmp-LongJmp which basically provides you with another exit strategy. The latter two are in system.
"Please don't fall into the trap of believing that I am terribly dogmatical about [the goto statement]. I have the uncomfortable feeling that others are making a religion out of it, as if the conceptual problems of programming could be solved by a single trick, by a simple form of coding discipline!"
—Edsger Dijkstra
Forgive me for a possible newbie questions..No problem. Asking questions are the simplest way of gathering knowledge, therefore, questions should be encouraged.
Isn’t goto just a holdover from assembly language jump command ?No, not really. The "goto" statement is a very general way of transferring control to someplace. It is very common in Assembly language because Assembly, usually, doesn't provide for/while/repeat loops nor high level conditionals. All of those must be synthesized using "goto"s or jumps of one kind or another (conditional, unconditional, indexed, etc.)
Also when using pascal without the goto, isn’t there still a goto being performed behind the scenes as part of the program flow?Yes, there is definitely one or more "goto" (or jumps) being performed behind the scenes BUT, in spite of that, it is _very_ different than an explicit "goto" instruction. The _crucial_ difference is that the target(s) of Pascal's "behind the scenes" jumps/gotos are pre-established. For instance, when a programmer sees a "for" loop - which is implemented using gotos/jumps - the programmer knows the very instant he/she sees the "for" statement that there is an execution scope that is limited by the end of the "for" statement. IOW, the "for" denotes an explicit execution boundary, the same is true of "while", "repeat", "if" and other instructions that are implemented using jumps/gotos.
Thanks for the clarification about the goto. My first two programming languages {Basic & FORTRAN } used numbered lines and required goto for just about everything. When I got to pascal I was told that pascal has a goto but never to use it because it wasn’t necessary. It was quite a surprise at the time that programming could be done without a goto...
"Please don't fall into the trap of believing that I am terribly dogmatical about [the goto statement]. I have the uncomfortable feeling that others are making a religion out of it, as if the conceptual problems of programming could be solved by a single trick, by a simple form of coding discipline!"
—Edsger Dijkstra