Main /
TomWikipediawikipedia article for editing onlyPhix is the open source?, self-hosted?, interpreted? and compiled? programming language? that emphasizes simplicity and programmer friendly error messages. || name || Phix || || logo || [[File:Phixlogo32.png|Phix logo]] || || caption || Phix logo || || paradigm || [[Imperative programming|Imperative, procedural]], [[object-oriented programming|object-oriented]] || || released || {{Start date and age|2006}} || || developer || Pete Lomax || || latest release version || 0.8.2 || || latest release date || {{Start date and age|2020|11|24}} || || typing ||[[Type_system#Static_type_checking|static]], [[Type_system#Dynamic_type_checking_and_runtime_type_information|dynamic]], [[Strong and weak typing|strong]], [[Duck typing|duck]] || || programming_language || [[Self-hosting_(compilers)|self-hosted]] || || operating system || [[Microsoft Windows|Windows]], [[Linux]], [[#Hello world, GUI|Browser]] || || genre || [[Interpreted language]] or [[compiled language]] || || license || [[Open_Software_License|Open Software License 3.0]] / [[Academic_Free_License|Academic Free License 3.0]] || || file_ext || .e, .ex, .exw, .edb || || influenced by || [http://openeuphoria.org/ Euphoria] || || website || {{URL|phix.x10.mx}} || History==Phix was released in 2006 based on the Euphoria? programming language written by Robert Craig in 1993. In 2013 Phix was re-written to replace the closed-source FASM? back-end with open-source inline assembly. || Version || Date || Key Features || 0.7.6 || Jul 2017 || try/catch,regex,json || 0.7.7 || Feb 2018 || ipc,serialise || 0.7.8 || Mar 2018 || zip || 0.7.9 || Apr 2018 || (maintenance release) || 0.8.0 || Apr 2019 || gmp,xml,sqlite || 0.8.1 || Mar 2020 || structs, classes || 0.8.2 || Nov 2020 || unit testing || 1.0 || mid-2021 || anticipated release Overview==Phix <ref name=softcat/> is designed to be simple, clear, and generic. The goal of Phix is to make writing programs, and then debugging easier. Phix is a hybrid interpreter/compiler: <ref name=hybrid/>
The is no extra step of a virtual machine interpreting bytecode? as with Python?. While compiling, some additional optimizations may be found, so a compiled program may run faster than an interpreted program. Phix extends the Euphoria tradition <ref name=linuxformat/> of "fast to read, fast to pickup and fast to run". Design Features===For new programmers:
<ref name=pGUI/>/IUP <ref name=IUP/>) out of the box.
<ref name=jspo/>).
<ref name=PCAN/> online archive, 500 bundled demos, and over 1250 entries on Rosettacode<ref name=phixrosetta/>. For experienced programmers:
<ref name=database/>, and SQlite <ref name=SQLite/>, <ref name=pSQLite/> wrappers.
<ref name=ipc/>, json? <ref name=json/>, curl <ref name=curl/>, zip <ref name=zip/>, gmp< ref name=gmp/>, regular expressions <ref name=regex/>, sockets <ref name=sock/>, and unit testing <ref name=unit/>. Data-Types==Phix only needs five primitive data types?: ┌────────┐ ┌─┤ object ├─┐ ✼ Five primitive data-types │ └────────┘ │ │ │ number sequence │ │ integer string └──────────┬─────────┘ │ ✼ Write your own ''type'' type to limit permitted values └────────────┬───────────┘ struct ✼ Reference data-types class provide dot-notation and OOP }}} Phix has a novel view of data-types; <ref name=novel/> you can do anything with just five data-types. All values are objects, "a constituent that is acted upon," while a data-type "limits permitted values." That makes a Phix @@object@@ the ''unlimited'' data-type. There are only two distinct data-types you must learn: number and sequence. * An @@object@@ is any value: number or sequence * A @@number@@ is an integer or a floating point numeric value ** An @@integer@@ is a whole number (in the range ±1,000,000,000 ) ** An @@integer@@ is also a @@number@@ * A @@sequence@@ is a list of values, of any length, and of any nesting level. ** A @@string@@ corresponds to UTF8 encoding; a list of character or byte values ** A @@string@@ is also a @@sequence@@ A @@type@@ is a user defined data-type. It is used to declare variables and for type-checking values as programs execute. Because it is programmable, you can add extra features beyond type-checking. For example, you could issue user created error messages. The reference data-types, @@struct@@ and @@class@@, deliver dot notation and OOP behavior. The complexity of memory allocation and de-allocation is hidden and handled automatically by reference counting. The programmer only sees that data-types appear to be simple. !! Symmetical Indexing== The @@sequence@@ is fundamental to the simplicity of Phix. Phix uses 1-based indexing because: * the first item is indexed is 1 * the last index n is equal to the length of the sequence * numbering from the head @@1 ... n@@ is symmetrical to numbering from the tail @@-n ... -1@@ * when searching for an item, an index value of 0 means "item not found" * a slice is inclusive from the first index to the last index * there are no off-by-one complications as found with 0-based indexing Sequences with mixed values and strings work the same; both sequences and strings are mutable. There have been many debates <ref name=io0ah/> <ref name=jggd/> <ref name=hisham/> <ref name=luamis/> about the use of 0-based compared to 1-based indexing. Pointer based languages, and pointer arithmetic, as described by <ref name=EWD831/> by [[Edsger_W._Dijkstra|Edsger W. Dijkstra]], have their place. Phix has no pointers and has no need for 0-based indexing. {{{ -- is a line comment // is also a line comment // 1 2 3 4 5 -- index head to tail sequence s = { 10, 20, 30, 40, 50 } // -5 -4 -3 -2 -1 -- index tail to head // one item ? s[2] ? s[-4] -- output for both is: -----> 30 // slice of one item ? s[2..2] ? s[-4..-4] -- output for both is: -----> {30} // inclusive slice ? s[2..4] ? s[-4..-2] -- output for both is: -----> {30,40,50} // empty sequence ? s[3..2] ? s[-3..-4] -- output for both is: -----> {} // insert s[3..2] = {99} ? s -----> {10,20,99,30,40,50} // prepend and append s = { 10,20,30,40,50 } s[1..0] = {0} -- prepend s[$+1..$] = {6} -- append ? s -----> {0,10,20,99,30,40,50,6} s[0..-1] = {9999} -- append ? s -----> {0,10,20,99,30,40,50,6,9999} // delete s = { 10,20,30,40,50 } s[2..2] = {} -- item deleted ? s -----> {10,30,40,50} s[2..3] = {} -- slice deleted ? s -----> {10,50} The virtual space between items In "What’s the big deal? 0 vs 1 based indexing" <ref name=ssj01/> Steven Sagaert provides a simple explanation (for Julia?): That’s exactly it. 1-based indexing is actual indexing like in mathematics, while 0-based “indexing” isn’t indexing at all but pointer arithmetic. This comes from C where an array is just syntactic sugar for a pointer. One-based indexing provides: intuitive and comprehensive operations not possible with 0-based indexing), and that work identically for sequences and strings. Parameter passing==All arguments are used as if they are passed as pass-by-value?.
An function set55(sequence s) s[5][5] = 5 return s end function sequence a,b // Case I a = repeat(repeat(0,5),5) -- a 5x5 matrix ? a --> {{0,0,0,0,0},{0,0,0,0,0},{0,0,0,0,0},{0,0,0,0,0},{0,0,0,0,0}} // Case II b = a ? b --> {{0,0,0,0,0},{0,0,0,0,0},{0,0,0,0,0},{0,0,0,0,0},{0,0,0,0,0}} // Case III b = set55(a) ? b --> {{0,0,0,0,0},{0,0,0,0,0},{0,0,0,0,0},{0,0,0,0,0},{0,0,0,0,5}} In Case I, sequence In Case II, sequence In Case III, sequence Here <font color="#008080">function</font><font color="#000000"> set55</font><font color="#0000FF">(</font><font color="#004080">sequence</font><font color="#000000"> s</font><font color="#0000FF">)</font> <font color="#000000"> s</font><font color="#0000FF">[</font><font color="#000000">5</font><font color="#0000FF">][</font><font color="#000000">5</font><font color="#0000FF">] =</font><font color="#000000"> 5 </font> <font color="#008080"> return</font><font color="#000000"> s </font> <font color="#008080">end function</font> <font color="#C0C0C0"></font> <font color="#004080">sequence</font><font color="#000000"> a</font><font color="#0000FF"> =</font><font color="#7060A8"> repeat</font><font color="#0000FF">(</font><font color="#7060A8">repeat</font><font color="#800000">(</font><font color="#000000">0</font><font color="#0000FF">,</font><font color="#000000">5</font><font color="#800000">)</font><font color="#0000FF">,</font><font color="#000000">5</font><font color="#0000FF">),</font><font color="#000080"><i> -- a 5x5 matrix</i></font> <font color="#000000"> b</font><font color="#0000FF"> =</font><font color="#000000"> set55</font><font color="#0000FF">(</font><font color="#000000">a</font><font color="#0000FF">)</font> Automatic PBR optimisationIt is idiomatic use a sequence as an argument to a function and then immediately assign the result back to that sequence: function chop( sequence a ) for i=1 to length(a) do a[i] = truncate(a[i]) end for return a end function sequence a = { 1.1, 2.2, 3.3, 4.4, 5.5 } a = chop(a) ? a --> { 1,2,3,4,5} Here the compiler applies a special optimization to make the local variable undefined over the call, leaving the parameter with a refcount of 1 and therefore amenable to in-situ modification. In general, when parameters are modified locally (within the routine), sequences and sub-sequences are implemented very efficiently, because of copy-on-write? semantics. Reference typesIn contrast class mytest public string s end class procedure change(mytest c, d) c = new({"c"}) d.s = "d" end procedure mytest a = new({"a"}), b = new({"b"}) change(a,b) ? a.s --> "a" ? b.s --> "d"
The statement Examples==Line comments start with a double hyphen Block comments start with Hello world, console====puts(1, "Hello, World!\n") <font color="#7060A8">puts</font><font color="#0000FF">(</font><font color="#000000">1</font><font color="#0000FF">,</font><font color="#008000"> "Hello, World!\n"</font><font color="#0000FF">)</font> Hello world, GUI====include pGUI.e IupOpen() IupShow(IupDialog(IupVbox({IupLabel("World!")},"MARGIN=90x20"),"TITLE=Hello")) if platform()!=JS then IupMainLoop() IupClose() end if <font color="#008080">include</font><font color="#000000"> pGUI.e</font> <font color="#5E005E">IupOpen</font><font color="#0000FF">()</font> <font color="#5E005E">IupShow</font><font color="#0000FF">(</font><font color="#5E005E">IupDialog</font><font color="#800000">(</font><font color="#5E005E">IupVbox</font><font color="#800080">(</font><font color="#008080">{</font><font color="#5E005E">IupLabel</font><font color="#000080">(</font><font color="#008000">"World!"</font><font color="#000080">)</font><font color="#008080">}</font><font color="#0000FF">,</font><font color="#008000">"MARGIN=90x20"</font><font color="#800080">)</font><font color="#0000FF">,</font><font color="#008000">"TITLE=Hello"</font><font color="#800000">)</font><font color="#0000FF">)</font> <font color="#008080">if</font><font color="#7060A8"> platform</font><font color="#0000FF">()!=</font><font color="#000000">JS</font><font color="#008080"> then</font> <font color="#5E005E"> IupMainLoop</font><font color="#0000FF">()</font> <font color="#5E005E"> IupClose</font><font color="#0000FF">()</font> <font color="#008080">end if</font> <gallery widths="217px" heights="87px" mode=nolines> File:phix-hwwin.png|Windows desktop File:phix-hwlnx.png|Linux desktop </gallery> Simple function====include pGUI.e -- for CD_DEG2RAD function deg_to_rad(number deg) return deg*CD_DEG2RAD end function ?deg_to_rad(180) -- outputs 3.141592654 {} = deg_to_rad(360) -- explict discard rqd <font color="#008080">include</font><font color="#000000"> pGUI.e </font><font color="#000080"><i> -- for CD_DEG2RAD</i></font> <font color="#008080">function</font><font color="#000000"> deg_to_rad</font><font color="#0000FF">(</font><font color="#000000">number deg</font><font color="#0000FF">)</font> <font color="#008080"> return</font><font color="#000000"> deg</font><font color="#0000FF">*</font><font color="#004600">CD_DEG2RAD</font> <font color="#008080">end function</font> <font color="#0000FF">?</font><font color="#000000">deg_to_rad</font><font color="#0000FF">(</font><font color="#000000">180</font><font color="#0000FF">) </font><font color="#000080"><i> -- outputs 3.141592654</i></font> <font color="#0000FF">{} =</font><font color="#000000"> deg_to_rad</font><font color="#0000FF">(</font><font color="#000000">360</font><font color="#0000FF">) </font><font color="#000080"><i> -- explict discard rqd</i></font> User defined types====type index(object x) return integer(x) and x>0 end type index ndx = 5 ndx = -2 -- run-time error "type check failure, ndx is -2", plus source code file name and line number <font color="#008080">type</font><font color="#000000"> index</font><font color="#0000FF">(</font><font color="#004080">object</font><font color="#000000"> x</font><font color="#0000FF">)</font> <font color="#008080"> return</font><font color="#004080"> integer</font><font color="#0000FF">(</font><font color="#000000">x</font><font color="#0000FF">)</font><font color="#008080"> and</font><font color="#000000"> x</font><font color="#0000FF">></font><font color="#000000">0</font> <font color="#008080">end type</font> <font color="#000000">index ndx</font><font color="#0000FF"> =</font><font color="#000000"> 5</font> <font color="#000000">ndx</font><font color="#0000FF"> = -</font><font color="#000000">2 </font><font color="#000080"><i> -- run-time error "type check failure, ndx is -2", plus source code file name and line number</i></font> User defined types are used primarily for validation and debugging purposes, rather than being fundamentally different to the five core builtin types. String mutationStrings and sequences have the same behavior. Strings are fully mutable, with variable length slice substitution: string s = "food" ?s --> outputs "food" s[2..3] = "e" ?s --> outputs "fed" s[2..1] = "east" ?s --> outputs "feasted" <font color="#004080">string</font><font color="#000000"> s</font><font color="#0000FF"> =</font><font color="#008000"> "food" </font><font color="#0000FF"> ?</font><font color="#000000">s </font><font color="#000080"><i> -- outputs "food"</i></font> <font color="#000000">s</font><font color="#0000FF">[</font><font color="#000000">2</font><font color="#0000FF">..</font><font color="#000000">3</font><font color="#0000FF">] =</font><font color="#008000"> "e" </font><font color="#0000FF"> ?</font><font color="#000000">s </font><font color="#000080"><i> -- outputs "fed"</i></font> <font color="#000000">s</font><font color="#0000FF">[</font><font color="#000000">2</font><font color="#0000FF">..</font><font color="#000000">1</font><font color="#0000FF">] =</font><font color="#008000"> "east" </font><font color="#0000FF"> ?</font><font color="#000000">s </font><font color="#000080"><i> -- outputs "feasted"</i></font> Exception handling ====try integer i = 1/0 -- or, for example, throw("file in use") catch e ?e[E_USER] end try puts(1,"still running...\n") <font color="#008080">try</font> <font color="#004080"> integer</font><font color="#000000"> i</font><font color="#0000FF"> =</font><font color="#000000"> 1</font><font color="#0000FF">/</font><font color="#000000">0</font> <font color="#000080"><i> -- or, for example, throw("file in use")</i></font> <font color="#008080">catch</font><font color="#000000"> e</font> <font color="#0000FF"> ?</font><font color="#000000">e</font><font color="#0000FF">[</font><font color="#004600">E_USER</font><font color="#0000FF">]</font> <font color="#008080">end try</font> <font color="#7060A8">puts</font><font color="#0000FF">(</font><font color="#000000">1</font><font color="#0000FF">,</font><font color="#008000">"still running...\n"</font><font color="#0000FF">)</font> Output: "attempt to divide by 0" -- or "file in use" still running... Filtering====function odd(integer a) return remainder(a,2)=1 end function function even(integer a) return remainder(a,2)=0 end function ?filter(tagset(10),odd) -- ==> {1,3,5,7,9} ?filter(tagset(10),even) -- ==> {2,4,6,8,10} <font color="#008080">function</font><font color="#000000"> odd</font><font color="#0000FF">(</font><font color="#004080">integer</font><font color="#000000"> a</font><font color="#0000FF">)</font><font color="#008080"> return</font><font color="#7060A8"> remainder</font><font color="#0000FF">(</font><font color="#000000">a</font><font color="#0000FF">,</font><font color="#000000">2</font><font color="#0000FF">)=</font><font color="#000000">1</font><font color="#008080"> end function function</font><font color="#000000"> even</font><font color="#0000FF">(</font><font color="#004080">integer</font><font color="#000000"> a</font><font color="#0000FF">)</font><font color="#008080"> return</font><font color="#7060A8"> remainder</font><font color="#0000FF">(</font><font color="#000000">a</font><font color="#0000FF">,</font><font color="#000000">2</font><font color="#0000FF">)=</font><font color="#000000">0</font><font color="#008080"> end function </font><font color="#0000FF">?</font><font color="#5E005E">filter</font><font color="#0000FF">(</font><font color="#5E005E">tagset</font><font color="#800000">(</font><font color="#000000">10</font><font color="#800000">)</font><font color="#0000FF">,</font><font color="#000000">odd</font><font color="#0000FF">) </font><font color="#000080"><i> -- ==> {1,3,5,7,9} </i></font><font color="#0000FF">?</font><font color="#5E005E">filter</font><font color="#0000FF">(</font><font color="#5E005E">tagset</font><font color="#800000">(</font><font color="#000000">10</font><font color="#800000">)</font><font color="#0000FF">,</font><font color="#000000">even</font><font color="#0000FF">) </font><font color="#000080"><i> -- ==> {2,4,6,8,10} </i></font> Version control====requires("0.8.2") -- crashes on 0.8.1 and earlier requires(WINDOWS) -- crashes on Linux requires(64) -- crashes on 32-bit Specify what versions and/or operating systems are required to run the source code: <font color="#5E005E">requires</font><font color="#0000FF">(</font><font color="#008000">"0.8.2"</font><font color="#0000FF">) </font><font color="#000080"><i> -- crashes on 0.8.1 and earlier</i></font> <font color="#5E005E">requires</font><font color="#0000FF">(</font><font color="#004600">WINDOWS</font><font color="#0000FF">) </font><font color="#000080"><i> -- crashes on Linux</i></font> <font color="#5E005E">requires</font><font color="#0000FF">(</font><font color="#000000">64</font><font color="#0000FF">) </font><font color="#000080"><i> -- crashes on 32-bit</i></font> In the latter case, if you try to run a 64-bit-only program with a 32-bit interpreter, it will try to locate a suitable 64-bit interpreter and offer to re-run it with that (and vice-versa, for instance the older arwen and win32lib libraries are 32-bit only). Unit testing====test_equal(2+2,4,"2+2 is not 4 !!!!") test_summary() <font color="#5E005E">test_equal</font><font color="#0000FF">(</font><font color="#000000">2</font><font color="#0000FF">+</font><font color="#000000">2</font><font color="#0000FF">,</font><font color="#000000">4</font><font color="#0000FF">,</font><font color="#008000">"2+2 is not 4 !!!!"</font><font color="#0000FF">)</font> <font color="#5E005E">test_summary</font><font color="#0000FF">()</font> If all goes well, no output is shown, and the program carries on normally. You can easily force a summary to be output, quietly create a logfile, etc. <ref name=unit/> Error reporting====When a Phix program crashes, it produces a programmer-readable file, Error messages are made as clear as possible, for example C:\Program Files (x86)\Phix\demo\ilest.exw:43 in function strip_comments() type check failure, line is {"--","-- builtins/assert.e (an autoinclude).. At that particular point line was supposed to be a string, not a list of strings. Where possible the compiler tries to pre-empt that kind of run-time error with a compile-time error: C:\Program Files (x86)\Phix\demo\ilest.exw:43 in function strip_comments() line = 5 ^ type error (storing atom in string) Source level tracing====Place The program will then run until the condition ( Type based debugging====Suppose some table It would normally be very helpful to know where exactly the wrong contents were placed in that table. Edit and re-run with say: --sequence t = {} type badtable(sequence t) if length(t)>=3 and t[3]<17.2 then ?9/0 end if return true end type badtable t = {} <font color="#000080"><i>--sequence t = {}</i></font> <font color="#008080">type</font><font color="#000000"> badtable</font><font color="#0000FF">(</font><font color="#004080">sequence</font><font color="#000000"> t</font><font color="#0000FF">)</font> <font color="#008080"> if</font><font color="#7060A8"> length</font><font color="#0000FF">(</font><font color="#000000">t</font><font color="#0000FF">)>=</font><font color="#000000">3</font><font color="#008080"> and</font><font color="#000000"> t</font><font color="#0000FF">[</font><font color="#000000">3</font><font color="#0000FF">]<</font><font color="#000000">17.2</font><font color="#008080"> then</font> <font color="#0000FF"> ?</font><font color="#000000">9</font><font color="#0000FF">/</font><font color="#000000">0</font> <font color="#008080"> end if</font> <font color="#008080"> return</font><font color="#004600"> true</font> <font color="#008080">end type</font> <font color="#000000">badtable t</font><font color="#0000FF"> = {}</font> That will crash at the required point, producing an Note that Feature summary==Paradigms: imperative, procedural, optionally object-oriented Standardized: No, the manual includes the language specification Type strength: strong Type safety: safe Expression of types: explicit, partially implicit Type compatibility: duck Type checking: dynamic, static Parameter Passing Methods Available: copy on write, immutable reference, multiple returns Garbage collection: Reference counting Intended use: Application, Educational, General, High-level scripting, Text processing Design goals: Simplicity, Readability, Ease of use Unsupported features==Phix does not (although most can be emulated) directly support operator/builtin/function overloading, lambda expressions, closures, currying, eval, partial function application, function composition, function prototyping, monads, generators, anonymous recursion, the Y combinator, aspect oriented programming, interfaces, delegates, first class environments, implicit type conversion (of the destructive kind), interactive programming, inverted syntax, list comprehensions, metaprogramming, pointers (other than to raw allocated memory), topic variables, enforced singletons, safe mode, s-expressions, or formal proof construction. The author wryly comments "That should both scare off and attract the right people" No operator overloading? means that No function overloading? refers to there being at most one (polymorphic) version of a routine in a given scope A simple and compact language is not limiting. Phix has some 1,277 <ref name=phixrosetta/> completed Rosettacode <ref name=rosetta/> tasks (second <ref name=phixsecond/> only to Go?). Criticism==The inline assembly on which Phix is based is x86/64 only, making an ARM port extremely difficult. The extensive run-time checking, which can increase productivity, incurs an inevitable performance penalty (at times a factor of 8), Type-checking can be reduced with the Floating point operations typically incur additional indirection and/or memory allocation cSompared to other languages. The use of inline assembly to alleviate runtime hotspots is both difficult to understand and poorly documented. Comparable languages==References==
External links==
Languages implemented in Phix==
{{DEFAULTSORT:Phix (programming language)}} :Category:Procedural programming languages? :Category:Cross-platform software? :Category:Programming languages created in 2006? :Category:Free educational software? |