Expand/Shrink

Phix vs Conventional Languages

By basing Phix on one, simple, general, recursive data structure, the sequence, a tremendous amount of the complexity normally found in programming languages has been avoided.
The arrays, structures, unions, arrays of records, multidimensional arrays, etc. of other languages can all be easily represented in Phix with sequences. So can higher-level structures such as lists, stacks, queues, trees etc.

Furthermore, in Phix you can have sequences of mixed type, and you can assign any object to an element of a sequence.
Sequences can easily grow or shrink in length without you having to worry about storage allocation issues.
The exact layout of a data structure does not have to be declared in advance, and can change dynamically as required.
It is easy to write generic code, where, for instance, you push or pop a mix of various kinds of data objects using a single stack.
Making a flexible list that contains a variety of different kinds of data objects is trivial in Phix, but often requires dozens of lines of ugly code in other languages.

Data structure manipulations are very efficient since the Phix interpreter just points to large data objects rather than copying them (aka shared references with copy-on-write semantics).

Programming in Phix is based entirely on creating and manipulating flexible, dynamic sequences of data.
Sequences are it - there are no other data structures to learn. You operate in a simple, safe, elastic world of values far removed from the rigid, tedious, dangerous world of bits, bytes, pointers and machine crashes.

Unlike other languages such as LISP and Smalltalk, Phix’s "garbage collection" of unused storage is a continuous process that never causes random delays in execution of a program, and does not pre-allocate huge regions of memory.

DEV (to be cleaned up)
                        C   C++  Go  Java  JavaScript  Julia  Lua  Python  Phix  Wren
Hassle free install:    Y-   N    Y-  N        Y         Y     N     Y      Y-    N
Easily portable code:   N    N    Y   Y-       Y         Y     ?     Y      Y     ?
Cross platform GUI:     ~    ~    N   Y        ~         Y-    Y     Y-     Y     Y
Runs on the desktop:    Y    ?    Y   Y        N         Y     Y     Y      Y     Y
Runs in a browser:      ~    ~    N   Y-       Y         N     Y     N      Y     N
Meaningful messages:    N    N--  Y   Y        N         Y     ?     Y-     Y     ?
Fast edit/run cycle:    ~    N--  N   N--      ~         N     Y     Y      Y     Y
Fast benchmark speed:   Y    Y    Y   Y        Y-        Y     ?     N--    N     N
Notes:
Installation of C/C++ ranges from absolutely easy peasy to a month-long struggle.
C-based languages are usually riddled with platform and compiler-specific #ifdefs.
Finding a bit of C/C++ code is often quite some distance from actually running it.
In my experience the majority of Go packages are out of date and incompatible
with the latest release, try installing IUP for Go, for example.
The only blotch on Phix install is (also) IUP on Linux, but no prob on Windows.
(O/c I have plans for a hassle-free Linux GUI, but don’t be holding your breath!)
Go’s packages are a valiant but somehow incomplete solution, certainly compared
to Julia’s Pkg.add() and Python’s pip install.
Phix does not currently have a third party package manager, but it should, and
instead relys more on having everything needed included in the standard distro.
(see demo/rosetta and bass/eulibnet/libxml for some fledgling ideas, perhaps,
as in entries that reference those subdirs rather than what’s actually in them)

While many C/C++ cross platform GUIs exist, only rarely does code cross-compile.
I have never managed to get a Go GUI running. While browsers are cross-platform,
the lack of a reasonable desktop GUI for JavaScript makes Y for it unacceptable.
Julia is a very impressive effort. Installing GTK on Windows is not excessively
difficult, but takes quite some time, and raises concerns about distribution of
finished applications. Likewise Python GUIs require a bit of manual setup effort.

Error messages from C++, if I get one at all, remind me of Dr Evil, in a cheesy
French accent: "There's a bug in your code" pause, then a dramatic "Somewhere!"
Whilst many JavaScript messages are fine, some are quite cryptic, and of course
in real terms most are just silently squirrelled away on a non-visible console.
Meaningful error messages are the heart and soul of Phix, simplifying debugging,
not that every bug is suddenly somehow easy, but at least it is trying to help.

Compilation times of an hour or even longer for C++ are still not exactly rare.
Claims that the Go compiler is fast confuse and bemuse me: a 90s delay compared to
a 0s delay for Phix is just simply not what I w/could describe as "very fast"...
JavaScript, or rather the Douglas Crockford subset of it, is actually a very good
language, but desktop is far from seamless, and it’s still somewhat harder to kill
off a bad run or infinite loop than I’d like - ie the Task Manager gets involved,
which to be fair can happen in Phix when running pw.exe w/o opening a console,
but puts(1,"") gives you a way out, nothing similar is available in JavaScript.

One thing Phix lacks is a proper register allocator, and as a consequence several
subscripting operations suffer more AGI stalls than they should. Work on p2js has
opened up the possibility of a better overall approach for some mythical v2.0.0.
Some (but not many, otherwise pointless) benchmarks can be up to 8 times faster
on C/Go/Julia, though you can at least hot-spot and use inline assembly on the
worst offenders, sometimes.

The language definitions of conventional languages such as C, C++, Ada, etc. are very complex.
Most programmers become fluent in only a subset of the language.
The ANSI standards for these languages read like complex legal documents.

You are forced to write different code for different data types simply to copy the data, ask for its current length, concatenate it, compare it etc.
The manuals for those languages are packed with routines that each only work on one of the many types of data, such as:
[1] strcpy, wcscpy, _tcscpy, lstrcpy[A/W], StrCpy, StringCbCpy, StringCbCpyEx, StringCchCpy, StringCchCpyEx, strncpy, _strncpy_l, wcsncpy, _wcsncpy_l, _mbsncpy, _tcsncpy, _mbsncpy_l,
[2] strcat, lstrcat[A/W], wcscat, _mbscat, strcat_s, wcscat_s, _mbscat_s, StrCat, StringCbCat, StringCbCatEx, StringCbCatN, StringCbCatNEx, StringCchCat, StringCchCatEx, StringCchCatN, StringCchCatNEx, strncat, _strncat_l, wcsncat, wcsncat_l, _mbsncat, _mbsncat_l,
[3] strcmp, lstrcmp[A/W], strncmp, wcsncmp, _mbsncmp, _mbsncmp_l, _strnicmp, _wcsnicmp, _mbsnicmp, _strnicmp_l, _wcsnicmp_l, _mbsnicmp_l,
[4] strlen, wcslen, _tcslen, lstrlen[A/W], _mbslen, _mbslen_l, _mbstrlen, _mbstrlen_l, strnlen, strnlen_s, wcsnlen, wcsnlen_s, _mbsnlen, _mbsnlen_l, _mbstrnlen, _mbstrnlen_l, StringCbLength, StringCchLength[A/W], UnalignedStringCchLength,
[5] strrchr, wcsrchr, _mbsrchr, _mbsrchr_l, etc.
Free free to google any or all of those, clearly I could be here for the rest of my life just simply listing them.
The (5) Phix equivalents for (all 77 of) that lot would simply be: [1] = (or :=), [2] & (or &=), [3] = (or ==), [4] length(), and [5] rfind(), admittedly the latter two perhaps with utf8_to_utf32() and similar.

Much of the complexity surrounds issues of data type.
How do you define new types?
Which types of data can be mixed?
How do you convert one type into another in a way that will keep the compiler happy?
When you need to do something requiring flexibility at run-time, you frequently find yourself trying to fake out the compiler.

In these languages the numeric value 4 (for example) can have a different meaning depending on whether it is an int, a char, a short, a double, an int * etc. In Phix, 4 is the atom 4, period. Phix also has user defined types as we shall see later, but they are a much simpler concept, used mainly for validation and debugging.

Arithmetic operations in Phix always generate sensible answers, and terminate the program with a human readable error message should they go badly out of range.
For instance 1/2 is always 0.5, rather than 0 or needing to be coded as 1.0/2.0.
Likewise zero minus one is always -1, not (on a 32-bit architecture) +4GB as can happen in C-based languages, and #100_0000 * #10_0000 is #1000_0000_0000 (which will trigger an error if stored in an integer instead of an atom), whereas C-based languages silently yield 0, and 1,000,000*100,000 yields an almost completely meaningless 1,215,752,192 in C, because it quietly discards the leading #17_0000_0000.
If you need to replicate such (wierd) math behaviour of C (eg in cryptographic routines) then you must explicitly apply the appropriate mask, eg and_bits(x,#FFFFFFFF), floor(x), trunc(x), ceil(x), in those few special cases where it is required.
(Note that imnsho, not that I practice what I preach, translating working C code is pretty much always a mugs game: you are far better off spending that time learning to build a dll/so and invoking that, and if you hit problems find a better version or a prebuilt one.)

Issues of dynamic storage allocation and deallocation consume a great deal of programmer coding time and debugging time in these other languages, and make the resulting programs much harder to understand.
Programs that must run continuously often exhibit storage "leaks", since it takes a great deal of discipline to safely and properly free all blocks of storage once they are no longer needed. (The same can be said for Phix code that interfaces to other languages, but not for normal hll code.)

In most C based languages, strings are "immutable".
In Phix, you can modify strings any way you like, everything is automatically taken care of for you, and all with no nasty surprises.
Note, however, that in Phix you are expected to say str = modified(str), rather than modify(str).
On that note, when reading Phix code it is always absolutely clear what is being mofified; you are not expected to continuously assume that arguments to routines might be modified, or hope and pray they are not.

True fact: the given answer for the question "describe what f(a++) does" in "More Exceptional C++" lists 4 possibilities for f, and 3 for a (so 12 in total) and uses the phrase "could mean just about anything" not once but twice - shudder.

In other languages pointer variables are extensively used.
The pointer has been called the "go to" of data structures.
It forces programmers to think of data as being bound to a fixed memory location where it can be manipulated in all sorts of low-level, non-portable, tricky ways. A picture of the actual hardware that your program will run on is never far from your mind.
Except when needed to invoke routines written in other languages, and even then only as a normal atom value, with no special syntax, Phix does not have pointers and does not need them.

These days it disturbs me to think that C and C-based languages fundamentally cannot [dynamically] distinguish an integer from a string. The latter is held as a char*, so if you have a machine-word-sized value such as #0124000 you have no idea whether that is really the (decimal) integer 1,196,032 or the string "Hello there". Of course the C type system can be quite helpful in such regards at compile-time, but at run-time it has simply gone. I suppose you could explicitly tag things, at some not inconsiderable cost to integer maths. One thing that makes ridiculously difficult is a properly polymorphic routine: the compiler may use templates and/or some form of koenig lookup to select between overloaded or auto-duplicated routines at compile-time, but there is no chance of that happening at runtime. A similar thing is that (except when explicitly terminated) almost every time you pass an array in C you also have to pass the length, and in a similar way you w/could say "next param is an integer" or "next param is a string", rather often. If you live in such a world you get used to it, but while the blind/deaf learn to cope, no-one would ever deliberately choose that.