Hacker News new | past | comments | ask | show | jobs | submit login
Why Pascal Is Not My Favorite Programming Language (1981) (liu.se)
31 points by dsego on Feb 25, 2019 | hide | past | favorite | 55 comments



This article pops up every now and again. Most of the criticisms are no longer valid. Pascal has moved on in the last 38 years.

If you don't know modern Pascal then check out Free Pascal, Lazarus, and Delphi:

https://www.freepascal.org/

https://www.lazarus-ide.org/

https://www.embarcadero.com/products/delphi

(And Delphi documentation at http://docwiki.embarcadero.com/ )


Specifically, just two years after the title text was written, in 1983, there was already Turbo Pascal which was much more useful than the language as defined for the introductory university classes:

http://edn.embarcadero.com/article/20693

It was the fastest compiler and environment of the time, but additionally, even before 1983, the "minimal" form of the language, suitable for teaching, was almost never used in production. What was used in production did have the necessary extensions which allowed having some very good software, with provably less bugs than C, because the basis was good and safer.

See also MacPaint, developed also around 1983 ("finished in October 1983"), in Apple Pascal:

https://www.computerhistory.org/atchm/macpaint-and-quickdraw...

Even Go language took its influences from Pascal, "rediscovering" some aspects that were obviously better (for the humans writing programs) than C.


Actually the influence of the Pascal family and that of the C family are about equally significant, if you go by the chart from the "Go Programming Language" book (available in the free preview, page xiii https://www.amazon.com/Programming-Language-Addison-Wesley-P...). Most significant is probably the module system, which, in good Turbo Pascal tradition, allows Go to run loops around other C-family languages (looking at you Rust ;) ), and of course the declaration syntax ("i int" instead of "int i").

Since I first came across Go I've been thinking that a Go-based Delphi clone would be really amazing. Maybe someone could breathe some new life into the Lazarus IDE by adding support for Go? Hmmm, actually there already is something: https://github.com/ying32/govcl - probably worth keeping an eye on...


I think Go was more influenced by Pascal's descendent's notably Oberon-2 (Pascal ->Modula 2/3 ->Oberon) thanks to Robert Griesemer, but definitely an indirect but significant influence.


> Pascal has moved on in the last 38 years.

How many of these extensions are in ISO Pascal, though?

ISO Pascal was last updated in 1990 (ISO 7185:1990); there is evidently an ISO/IEC 10206:1991, a standard for "Extended Pascal". This Extended Pascal 1991 standard was evidently reviewed in 2008 and affirmed as-is.

FreePascal has a Wiki page about Extended Pascal:

http://wiki.freepascal.org/Extended_Pascal

I see a lot of "(not yet implemented)".


Also the open source .Net relatives PascalABC.Net and and the Oberon family inspired Component Pascal if you are looking for Pascal related languages on .Net/Mono/Core.


Amazing, our Oxygene compiler, Delphi and FPC has solved all of these issues ages ago, perhaps it's time to let this article go after all this time.

- 2.0 Types and scopes: Apple = type Integer; makes it a distinct type

- 2.1 Array size: dynamic arrays

- 2.2 Admittedly, not exactly solved, but classes are how we hide variable these days.

- 2.3 Oxygene doesn't care about order of things

- 2.4: Long solved

- 2.5: While allowed; something can be said for using an alias here to make the intent obvious; the in set is also solved in Oxygene since c in ['a'..z'] compiles to c >='a' and c <='z'.

- 3: boolean shortcircuitry has long been part of Pascal

- 4: With streams apis this is no longer a thing

- 5: xor/or has lng been part of the languages, the semicolon issue seems a style issue to me, not a big deal

(edit: had to insert enters to make it readable)


I've used Delphi in the last year and, while I hated it overall, there were a few things I liked about it. It's really nice that it compiles so quickly. And it feels very principled, at least the Pascal baseline.

The main problem I remember is that you cannot simply use pointer types, or other complex types, as function parameters. You always have to declare a typedef first, such that the type that is used in the function signature is a single word (named reference to the typedef).

Working on a compiler myself, I understand from an implementation perspective why Wirth did this, but this is really lazy. From a developer's perspective, to me that's next to unusable. It's really stressful to predeclare pointer types before using them, and using names like TypeP, TypePP and so on is much less readable than simple ^Type, ^^Type, etc.

Another thing that's driving me crazy is case insensitivity. I would never willfully choose a language with case insensitive identifiers. It's driving me nuts.

> 2.2 Admittedly, not exactly solved, but classes are how we hide variable these days.

global initialized variables are really important to me to avoid unnecessary boilerplate and indirection (which is just as painful as not having initialized globals). What I did was initialize them in the initilization section. But it was another major inconvenience.


> It's really stressful to predeclare pointer types before using them

Depending on what you're doing exactly there are things you can do to mitigate that. If you're using records, you can just pass the record by reference instead. If you're using objects then you don't often need separate pointer types to them (the object reference is a pointer itself). If it makes sense for what you're doing you can also use untyped parameters:

http://docwiki.embarcadero.com/RADStudio/Rio/en/Parameters_(...

If you don't need to actually deference the pointers you can use the Pointer type (and if you still need to get at the data in some circumstances you can cast to a typed pointer inside the function):

http://docwiki.embarcadero.com/RADStudio/Rio/en/Pointers_and...


Yes I know these workarounds but I don't think they are better than typedefs. Instead I simply want the obvious and readable thing that doesn't try to hide what happens and that doesn't require extra keyboard typing.


> I don't think they are better than typedefs

Why? Passing a record by reference looks like this: procedure SomeProc(var AMyRec : TMyRecord);

Passing an object reference looks like this: procedure SomeProc(const AMyObj : TMyObject);

I don't see that these are somehow onerous or hiding anything.


Sure. When used they look like normal variables. And when you set them it looks like setting a local variable. This is hiding that what really happens is it's writing through a pointer. And it's modifying the caller's state.

Add to that the unfounded non-orthogonality (like in C++, references are technically the same as pointers, but not syntactically, and not in the type system, leading to combinatorial explosion. And of course the bloated standard library is proof).

Furthermore this approach doesn't work for pointers that point to arrays. Again, Delphi has its own zoo of workarounds that OOP enthusiast will think are so much better -- from dynamic arrays (really weird interactions with reallocations combined with "var" modifier or not), to ObjectLists (not typed) to a version of generics (has its own technical problems). But what I want is the simple and obvious thing (pointer parameters without typedefs) and there's no good reason why we shouldn't have it.


> This is hiding that what really happens

There is no ambiguity and nothing is hidden. Both examples are passing a reference to the procedure and all Pascal programmers will know what it means.

I think your argument boils down to a lack of experience with Pascal (which is fine). But these things you think are problems simply aren't.


The pointer alias requirement is something we got rid of in our language (oxygene). We even allow defining method pointer types inline, though I wouldn't ever do that myself in a method signature, it's quite useful inside a structure, especially when doing com like or jni interop.

Case insensitive, our compiler by default warns about mismatches between definition and use.

Initialization is there, what I meant is that we don't have something where you define a static var inside a method body. You can of course make it implementation only or private which can severely limit the scope of what can access it.


> Another thing that's driving me crazy is case insensitivity. I would never willfully choose a language with case insensitive identifiers. It's driving me nuts.

What about it annoys you? Do you often define a lot of variables whose names differ only by case, in languages that let you? Common Lisp normally behaves as though it were case insensitive, and I've never found that to be a pain point.


In fact I often use the "Thing thing" approach to variable declaration and I think I like it. It's an easy way for me to avoid thinking about taxonomy. But it's not that important. If it wasn't possible I could invent different names.

What really irks me is that in case-insensitive languages, codebases naturally start to use all kinds of variations of casing, to refer to the same variable. It really trips me up when reading code. It's also difficult when writing code since I tend to remember variable names in a very visual way. (Same reason why I dislike the case-insensitive Windows filesystems).

There simply isn't any good reason not to always use the same case for any variable throughout a project.

Beyond that it's also aesthetically not pleasing, from an engineering viewpoint. Case-insensitive comparison is much more complicated than simply comparing strings as arrays of bytes.

Historically, I think the reason why case-insensitive languages exist is simply that at the time they were invented (at least in the case of Pascal), many systems couldn't input lowercase characters.


> In fact I often use the "Thing thing" approach to variable declaration and I think I like it. It's an easy way for me to avoid thinking about taxonomy. But it's not that important. If it wasn't possible I could invent different names.

There's no reason that types and variables need to live in the same namespace. The language can know what it's expecting at a certain point. Putting them in different namespaces, like Lisp does, lets you re-use the same name for types and variables even with matching case, and is more waterproof with regards to clashes than a case convention.

> There simply isn't any good reason not to always use the same case for any variable throughout a project.

I agree, but I also feel that there isn't any good reason to have multiple distinct objects in the same namespace whose names differ only by case. It just seems like a recipe for confusion.

When I'm quickly iterating on something, it's nice being able to be lazy and inconsistent with capitalisation. Standardising that in a codebase is important, but it's more of a job for a linter, I think.


Yes, C has that too. It has different namespaces for struct, union, and enum. And I like the clarity of the explicit namespace prefixes at each place of reference. But I tend to not rely on that distinction, since C++ has only a single namespace.

And as soon as we go to more dynamic languages, where types can also be variables, it all breaks down.


I was just saying that there's no good reason to have different variables with names that only differ by case; the example you gave where you do like that has a better solution in multiple namespaces.


Problem there is that it would disallow Type.Staticmember or Type(value) kind of casts, which do exist in most Pascal languages.


> I often use the "Thing thing" approach to variable declaration

The Pascal way would be to use the "T" convention for the name of the type. So "thing : TThing".


Yes, but it's one extra verbose character, and it's also not a waterproof systematic. E.g., the type "THat" would clash with the variable "that". Instead I want the simple, obvious, and reliable thing: string comparison is comparison of byte arrays. No problems.


Case insensitivity is simply not a practical problem. The "THat" versus "that" scenario won't compile and is trivial to address.


My point is that the systematic is an inferior workaround to the obvious case-sensitive approach that would be simpler to implement, simpler to explain, and wouldn't have any of these problems to begin with. It's completely pointless.

Maybe people who somehow don't differentiate between 'T' and 't', and are not visually remembering persons, don't have this problem. But for me, and for computers, they are different characters.


I never understood the falsification with case insensitive languages, to me it was yet another way to trip up a team effort let alone working with many related sources.

however my view is jaded by working mostly on minis and our languages were always this way. the focus was on concise naming and logic and to me just adding another method for a typo to nail me does not benefit a language.

so can someone tell me the reason why?


REAMS OF UPPER CASE is what is annoying!

You should almost never use it in programming, unless you mean it. I've never written Common Lisp code in upper case, other than copying and pasting from REPL output.

Allowing upper case to simply denote lower case any time you want basically PANDERS TO THE MORONS WHO SHOUT LIKE THIS in internet forums.

Supporting case insensitivity in a modern setting requires carrying a large table of Unicode data about all of the world's scripts that exhibit case.

Which scripts exhibit case is controversial. Are Japanese hiragana and katakana in a case relationship? Should れつ (retsu) and レツ (RETSU, sort of) be the same symbol or not?

Programmers used to case distinctions see FOO, Foo and foo as completely different; there is no issue there. Literate non-programmers should also see them as different. "Pat" is a name, "pat" is a verb.

Mathematics uses case distinction. If you're writing a summation notation with Σ, you can't just switch to σ. You can't switch 3 + 4i to 3 + 4I just because you feel like it.

Basically, case insensitivity is for illiterate morons with no background in mathematics.

Why it appears in classical programming languages is because 1950's and 1960's hardware didn't support large enough character sets to have both upper and lower case. Even some consumer grade microcomputers in the late 1970's and early 1980's lacked lower case, like Apple II's.

The Unix TTY system still supports folding to upper case!

Try this at your Linux bash prompt:

   $ stty olcuc  # output: lower case to upper case
the reverse conversion is available on input.

Thus, old programming languages were written in upper case, but with increasing support for lower case in character sets and hardware, programmers wanted to use those same languages in lower case. A pragmatic solution was to support it both ways: allow lower case for new programs, but also upper case for backward compatibility with existing code.

So it wasn't illiteracy; there was a technical reason. The technical reason doesn't exist any more, and so repeating this in new designs is just illiteracy. If you're making a new language today, you have no existing code in upper case that has to work.


>I would never willfully choose a language with case insensitive identifiers.

If you run into name collisions between FooBar and fooBar due to case insensitivity, isn't that indicative of your naming scheme for variables and functions, rather than a fault in the language design?


You mean I shouldn't make both a function FooBar and a variable fooBar? Not the worst rule probably. We shouldn't get to clever with casing. Which is why I use mostly lowercase (to avoid decision paralysis).

However, the language problem I see is when I define something as FooBar and reference it as FoOBAr or FOOBAR and that is not a symbol-not-found error.


Amazing, our Oxygene compiler, Delphi and FPC has solved all of these issues ages ago...

What does that (partial) sentence mean?

Your Oxygene compiler (which is called Delphi) as well as “FPC” have both solved all of these issues ages ago?

That seems wrong because Delphi is a Pascal descendent. But otherwise I don’t know how to parse that partial sentence.

What are Oxygene and FPC?


Should have been 'have'. Oxygene, FPC (freepascal) and Delphi are 3 different Pascal compilers which all have solved most/all of these problems.


I just thought I'd give your product a try. My hopes are very high, since at $800 I expect something almost on a par with Delphi. CrossBox seems like a neat idea but it would be great to explain upfront that in order to develop for other platforms you actually need to have that machine. It's half-cross-platform, I'd say.


We're working on making the osx target be able to compile locally, but it's a slow process. A beta backend can now create osx executables from windows without running osx. There however are a lot of things that are closed tools that are osx only, like Ibtool, codesign etc, a lot of which are required parts of getting a final application. While we're working on getting around those, osx will be required to compile yes. Obviously debugging Will stay dependent on osx. (Also iOS will require osx due to how it's not possible to upload and debug apps from windows at all). That said I agree that should be made more clear.


I believe even in 80s most of these were fixed in various 3rd party vendor Pascal compilers.

Anyway, I've always found your particular products/business interesting. Could you please share some insights? Like who are your userbase (I believe you're in a very niche space, but I might be wrong), how strong are sales going on, etc...


We don't usually share information about sales, as that is confidential business data, but suffice to say we're pretty happy and are going strong for ~15 years, now.

Our users come from all ranges, both in terms of company size (from single-dev shops to big-name Fortune 500s) and target area (mobile, desktop, web, services, enterprise, you name it). Elements is a general purpose programming environment, and I believe there's something to find and like about it for just about every software developer.

For example, while we have a strong focus on sharing code across platforms, the product is nit just about that, a lot of developers single-platform devs still love Elements for other reasons, even if they only care about, say, .NET, or only about Cooca. The multi-platform support is just one of a list of many benefits any individual dev might be attracted to (or not care about).

—marc


> - 2.2 Admittedly, not exactly solved, but classes are how we hide variable these days.

You can use a const in a function and wrap it in {$J+} to allow modifying consts. And that's a static variable on that function (or procedure), e.g.

{$J+}

procedure A; const C: integer = 0; begin Inc(C); Writeln(C); end;

{$J-}


Good thing that we aren't using languages the way they were in 1981 anymore.

As for Pascal, TurboPascal has been revolutionary, and it came out in 1983, two years after this article came out. TP, the lightning-speed IDE, debugger and compiler in one small executable pushed Pascal to its peak popularity; Delphi was another revolution.

These days, Lazarus would be the go-to modern Pascal successor. (Delphi is still here, but is very much non-free; Lazarus is FOSS).


Someone told me TurboPascal was actually Modula-2 just named "Pascal" for marketing. Where they wrong?


Yes.

Most obviously Modula-2 is is case-sensitive, while (Turbo)Pascal is not. Also Modula-2 addresses the danging-else problem in Pascal, while TurboPascal does not.

It wouldn't surprise me if TurboPascal addressed some of the same deficiencies in Pascal that Wirth also addressed in Modula-2, but they probably do so differently.


No, it was definitely Pascal. There's certainly quite a lot of stylistic crossover between the two languages but they are distinct.


My usual shoutout to Lazarus/FreePascal go here: They're really wonderful, modern, well-maintained and ready for professional work.

If you've experienced 100MB Electron garbage and are tired of it, or you think C++ is a tangled mess and want no part in it, and you need something LGPL that has a wonderful community, check it out.


It's an interesting read and at the same time a relief to realize that many if not most of the problems have been addressed years ago. E.g. sorting an array in FreePascal is a very simple task (not to mention that dynamic arrays and generics are also supported).


And in the recent versions of Delphi you can use TArray which supports generics and simply call its Sort method:

http://docwiki.embarcadero.com/Libraries/Rio/en/System.Gener...

It's a shame more people don't use Object Pascal. I like it a lot.


It's funny that generics are supported in Pascal, but not in its spiritual successor, Go.

(Of course, Go's succession goes not directly from Pascal, but through Modula-2 and Oberon.)


Delphi has compile-time generics, which is kind of a "worst of both worlds" approach. It has all the constraints of templates, but none of the benefits of run-time instantiated generics like .Net has.

For example you can't make a generic function that uses the + operator to add two parameterized elements together, because there's no way to constrain the types to only those which has the + operator defined. But unlike templates in C++, the compiler doesn't just try and see if it works but rather emits an error.


is the discussion about Generics over in golang-dev ?


I was indoctrinated by this text. A fan of C and C style languages.

And I feel this was so wrong and that the world could be a better place if we would have turned into another direction.


It happened to me, too. This and several other cases demonstrate the value of independent thinking, investigating the matter yourself rather than following the crowd. This is happening also these days: two years ago it was Big data, last year it was microservices and "serverless" and so on.


and so on.

Back until the dawn of computing. And the dawn of technology before that. And the dawn of humankind before that. And so on.


I used to be a language snob until I realized that the choice of language is pretty much irrelevant. What counts is the tooling, the available libraries and framework, and sometimes also how fast the compiler and the executables are.


If anyone cares for an overview of Lazarus and Free Pascal, here are a few resources:

https://www.getlazarus.org/new/

https://www.getlazarus.org/learn/language/lexical/

... and the searchable online reference:

http://docs.getlazarus.org/#rtl+system+tobject#


For those interested, Oberon is the current Pascal. It is also designed by Niklaus Wirth. I use the OBNC compiler (https://www.miasap.se/obnc).


Perhaps in a way, OBNC is the successor to Pascal considering Pascal's history with Niklaus Wirth, but then, Delphi appears to be a better candidate for being the "current pascal" considering Anders Hejlsberg's commercial success in creating widely-adopted languages.


OBNC is just a compiler. Whereas other languages evolve by adding more and more features, Oberon seem to converge to a set of features which are tried, tested, orthogonal and (most important) essential. Wirth has been very careful not to introduce any misfeatures.


I really miss Pascal and Delphi. They're beautiful.


You don't have to - they're still around




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: