The `Container` class is widely misunderstood and underused. However it can be very useful to implement a return parameter. This PR rename the class according to this usage. It will make some signatures easier to understand: (example inspired by a similar function from `UDPSocket`)
~~~nit
# This method has 3 outputs:
# * The received message written into `buffer`.
# * The number of bytes written as the return value.
# * The information on the sender of the message is stored in `sender_info`.
fun recv_from(buffer: NativeString, sender_info: Ref[nullable SocketAddress]): Int
~~~
### Bonus Ref tip!
`Ref` can also be used as a hackish equivalent to a `static` variable in C. This example use the dreaded `once` keyword to easily get a singleton, but it could be done cleaner with an attribute in `Sys`.
~~~nit
fun foo
...
# Count the number of times foo is executed
var counter = once new Ref[Int](0)
counter.item += 1
print "foo has been executed {counter.item} times"
end
~~~
Pull-Request: #1573
Reviewed-by: Lucas Bajolet <r4pass@hotmail.com>
Reviewed-by: Alexandre Terrasa <alexandre@moz-code.org>
Reviewed-by: Jean Privat <jean@pryen.org>
--- /dev/null
+#!/usr/bin/env nit
+#
+# This file is part of NIT ( http://www.nitlanguage.org ).
+# This program is public domain
+
+# Task: Entropy
+# SEE: <http://rosettacode.org/wiki/Entropy>
+module entropy
+
+import counter
+
+# Basic implementation with a hashmap of chars to count them
+fun entropy(string: String): Float
+do
+ var cpt = new HashMap[Char, Int]
+ for char in string.chars do
+ var occ = cpt.get_or_default(char, 0)
+ cpt[char] = occ + 1
+ end
+
+ var len = string.length.to_f
+ var e = 0.0
+ for char, occ in cpt do
+ var freq = occ.to_f / len
+ e = e - freq * freq.log_base(2.0)
+ end
+ return e
+end
+print entropy("1223334444")
+
+# Alternative one-liner implementation using the `Counter::entropy` method of the library `counter`
+print "1223334444".chars.to_counter.entropy
--- /dev/null
+#!/usr/bin/env nit
+#
+# This file is part of NIT ( http://www.nitlanguage.org ).
+# This program is public domain
+
+# Task: Entropy/Narcissist
+# SEE: <http://rosettacode.org/wiki/Entropy/Narcissist>
+module entropy_narcissist
+
+import counter
+
+# Should be run in the right directory
+print "entropy_narcissist.nit".to_path.read_all.chars.to_counter.entropy
--- /dev/null
+#!/usr/bin/env nit
+#
+# This file is part of NIT ( http://www.nitlanguage.org ).
+# This program is public domain
+
+# Task: Fibonacci_word
+# SEE: <http://rosettacode.org/wiki/Fibonacci_word>
+module fibonacci_word
+
+import counter
+
+var words = new Array[String]
+words[0] = ""
+words[1] = "1"
+words[2] = "0"
+
+for i in [1..37] do
+ var w
+ if i >= words.length then
+ w = words[i-1] + words[i-2]
+ words[i] = w
+ else
+ w = words[i]
+ end
+ var out = w
+ if w.length > 40 then out = "..."
+ print "{i}\t{w.length}\t{w.chars.to_counter.entropy.to_precision(16)}\t{out}"
+end
end
return (sum / map.length.to_f).sqrt
end
+
+ # The information entropy (Shannon entropy) of the elements in the counter (in bits).
+ fun entropy: Float
+ do
+ var res = 0.0
+ var sum = self.sum.to_f
+ for k, v in self do
+ var f = v.to_f / sum
+ res = res - f * f.log_base(2.0)
+ end
+ return res
+ end
+end
+
+redef class Collection[E]
+ # Create and fill up a counter with the elements of `self.
+ #
+ # ~~~
+ # var cpt = "abaa".chars.to_counter
+ # assert cpt['a'] == 3
+ # assert cpt['b'] == 1
+ # assert cpt.length == 2
+ # assert cpt.sum == 4
+ # ~~~
+ fun to_counter: Counter[E]
+ do
+ var res = new Counter[E]
+ res.inc_all(self)
+ return res
+ end
end
private class CounterComparator[E]
init(ns, 0, 0)
end
+ # Init a `Bytes` with capacity `cap`
init with_capacity(cap: Int) do
var ns = new NativeString(cap)
init(ns, 0, cap)
end
end
+ # var b = new Bytes.empty
+ # b.append([0x41u8, 0x41u8, 0x18u8])
+ # b.pop
+ # assert b.to_s == "AA"
+ redef fun pop do
+ assert length >= 1
+ length -= 1
+ return items[length]
+ end
+
redef fun clear do length = 0
# Regenerates the buffer, necessary when it was persisted
end
redef class NativeString
+ # Creates a new `Bytes` object from `self` with `strlen` as length
fun to_bytes: Bytes do
var len = cstring_length
return new Bytes(self, len, len)
do
_index = _array.length - 1
end
+
+ # Do not cache `self`
+ redef fun finish do end
end
# Others collections ##########################################################
var v = new_visitor
var rta = runtime_type_analysis
- var is_dead = rta != null and not rta.live_classes.has(mclass) and not mtype.is_c_primitive and mclass.name != "NativeArray" and mclass.name != "Pointer"
+ var is_dead = rta != null and not rta.live_classes.has(mclass)
+ # While the class may be dead, some part of separately compiled code may use symbols associated to the class, so
+ # in order to compile and link correctly the C code, these symbols should be declared and defined.
+ var need_corpse = is_dead and mtype.is_c_primitive or mclass.kind == extern_kind or mclass.kind == enum_kind
- v.add_decl("/* runtime class {c_name} */")
+ v.add_decl("/* runtime class {c_name}: {mclass.full_name} (dead={is_dead}; need_corpse={need_corpse})*/")
# Build class vft
- if not is_dead then
+ if not is_dead or need_corpse then
self.provide_declaration("class_{c_name}", "extern const struct class class_{c_name};")
v.add_decl("const struct class class_{c_name} = \{")
v.add_decl("{self.box_kind_of(mclass)}, /* box_kind */")
self.header.add_decl("{mtype.ctype_extern} value;")
self.header.add_decl("\};")
- if not rta.live_types.has(mtype) and mtype.mclass.name != "Pointer" then return
+ # Pointer is needed by extern types, live or not
+ if is_dead and mtype.mclass.name != "Pointer" then return
#Build BOX
self.provide_declaration("BOX_{c_name}", "val* BOX_{c_name}({mtype.ctype_extern});")
v.add("return (val*)res;")
v.add("\}")
+ # A Pointer class also need its constructor
if mtype.mclass.name != "Pointer" then return
v = new_visitor
var pointer_type = mainmodule.pointer_type
self.provide_declaration("NEW_{c_name}", "{mtype.ctype} NEW_{c_name}(const struct type* type);")
- v.add_decl("/* allocate {mtype} */")
+ v.add_decl("/* allocate extern {mtype} */")
v.add_decl("{mtype.ctype} NEW_{c_name}(const struct type* type) \{")
if is_dead then
v.add_abort("{mclass} is DEAD")
end
return self.new_expr("((struct instance_{mtype.c_name}*){value})->value; /* autounbox from {value.mtype} to {mtype} */", mtype)
else if not mtype.is_c_primitive then
+ assert value.mtype == value.mcasttype
if value.mtype.is_tagged then
+ var res
if value.mtype.name == "Int" then
- return self.new_expr("(val*)({value}<<2|1)", mtype)
+ res = self.new_expr("(val*)({value}<<2|1)", mtype)
else if value.mtype.name == "Char" then
- return self.new_expr("(val*)((long)({value})<<2|2)", mtype)
+ res = self.new_expr("(val*)((long)({value})<<2|2)", mtype)
else if value.mtype.name == "Bool" then
- return self.new_expr("(val*)((long)({value})<<2|3)", mtype)
+ res = self.new_expr("(val*)((long)({value})<<2|3)", mtype)
else
abort
end
+ # Do not loose type info
+ res.mcasttype = value.mcasttype
+ return res
end
var valtype = value.mtype.as(MClassType)
if mtype isa MClassType and mtype.mclass.kind == extern_kind and mtype.mclass.name != "NativeString" then
valtype = compiler.mainmodule.pointer_type
end
var res = self.new_var(mtype)
- if compiler.runtime_type_analysis != null and not compiler.runtime_type_analysis.live_types.has(valtype) then
- self.add("/*no autobox from {value.mtype} to {mtype}: {value.mtype} is not live! */")
- self.add("PRINT_ERROR(\"Dead code executed!\\n\"); fatal_exit(1);")
- return res
- end
+ # Do not loose type info
+ res.mcasttype = value.mcasttype
self.require_declaration("BOX_{valtype.c_name}")
self.add("{res} = BOX_{valtype.c_name}({value}); /* autobox from {value.mtype} to {mtype} */")
return res
mtype.mclass.name != "NativeString" then
var valtype = compiler.mainmodule.pointer_type
var res = self.new_var(mtype)
- if compiler.runtime_type_analysis != null and not compiler.runtime_type_analysis.live_types.has(value.mtype.as(MClassType)) then
- self.add("/*no boxing of {value.mtype}: {value.mtype} is not live! */")
- self.add("PRINT_ERROR(\"Dead code executed!\\n\"); fatal_exit(1);")
- return res
- end
+ compiler.undead_types.add(mtype)
self.require_declaration("BOX_{valtype.c_name}")
self.add("{res} = BOX_{valtype.c_name}({value}); /* boxing {value.mtype} */")
self.require_declaration("type_{mtype.c_name}")
var i = 0
for p in spd.initializers do
if p != longest.initializers[i] then
- self.error(nclassdef, "Error: conflict for inherited inits {spd}({spd.initializers.join(", ")}) and {longest}({longest.initializers.join(", ")})")
+ var proposal = new ArraySet[MProperty]
+ for spd2 in spropdefs do
+ proposal.add_all spd2.initializers
+ end
+ proposal.add_all initializers
+ self.error(nclassdef, "Error: cannot generate automatic init for class {mclassdef.mclass}. Conflict in the order in inherited initializers {spd}({spd.initializers.join(", ")}) and {longest}({longest.initializers.join(", ")}). Use `autoinit` to order initializers. eg `autoinit {proposal.join(", ")}`")
# TODO: invalidate the initializer to avoid more errors
return
end
class D
super B
super C
- #alt3#var b: Int
+ #alt3,5#var b: Int
#alt4#var b = 11
init do 'd'.output #alt2#
end
super D
super E
init do 'f'.output #alt1,2#
+ #alt5#autoinit c=, e=
end
class G
super E
var g: Int
init do 'g'.output #alt2#
+ #alt5#autoinit c=, e=, g=
end
class H
blink
input
first_letter_last_letter
+fibonacci_word
blink
input
first_letter_last_letter
+fibonacci_word
-alt/base_init_basic_alt3.nit:47,7: Error: conflict for inherited inits base_init_basic_alt3#E#init(c=, e=) and base_init_basic_alt3#D#init(c=, b=)
-alt/base_init_basic_alt3.nit:53,7: Error: conflict for inherited inits base_init_basic_alt3#E#init(c=, e=) and base_init_basic_alt3#D#init(c=, b=)
+alt/base_init_basic_alt3.nit:47,7: Error: cannot generate automatic init for class F. Conflict in the order in inherited initializers base_init_basic_alt3#E#init(c=, e=) and base_init_basic_alt3#D#init(c=, b=). Use `autoinit` to order initializers. eg `autoinit c=, b=, e=`
+alt/base_init_basic_alt3.nit:54,7: Error: cannot generate automatic init for class G. Conflict in the order in inherited initializers base_init_basic_alt3#E#init(c=, e=) and base_init_basic_alt3#D#init(c=, b=). Use `autoinit` to order initializers. eg `autoinit c=, b=, e=, g=`
--- /dev/null
+alt/base_init_basic_alt5.nit:79,9--11: Error: expected 2 argument(s) for `init(c: Int, b: Int)`; got 1. See introduction at `standard::Object::init`.
--- /dev/null
+1.846
+1.846
--- /dev/null
+1 1 0.0000000000000000 1
+2 1 0.0000000000000000 0
+3 2 1.0000000000000000 01
+4 3 0.9182958340544894 010
+5 5 0.9709505944546686 01001
+6 8 0.9544340029249650 01001010
+7 13 0.9612366047228760 0100101001001
+8 21 0.9587118829771316 010010100100101001010
+9 34 0.9596868937742170 0100101001001010010100100101001001
+10 55 0.9593160320543778 ...
+11 89 0.9594579158386696 ...
+12 144 0.9594037542210228 ...
+13 233 0.9594244469559864 ...
+14 377 0.9594165437404406 ...
+15 610 0.9594195626031440 ...
+16 987 0.9594184095152248 ...
+17 1597 0.9594188499578102 ...
+18 2584 0.9594186817240320 ...
+19 4181 0.9594187459836638 ...
+20 6765 0.9594187214386752 ...
+21 10946 0.9594187308140276 ...
+22 17711 0.9594187272329618 ...
+23 28657 0.9594187286008076 ...
+24 46368 0.9594187280783368 ...
+25 75025 0.9594187282779028 ...
+26 121393 0.9594187282016752 ...
+27 196418 0.9594187282307916 ...
+28 317811 0.9594187282196702 ...
+29 514229 0.9594187282239182 ...
+30 832040 0.9594187282222962 ...
+31 1346269 0.9594187282229156 ...
+32 2178309 0.9594187282226794 ...
+33 3524578 0.9594187282227690 ...
+34 5702887 0.9594187282227344 ...
+35 9227465 0.9594187282227478 ...
+36 14930352 0.9594187282227430 ...
+37 24157817 0.9594187282227448 ...
-../lib/standard/bytes.nit:49,7--19: Documentation warning: Undocumented property `with_capacity`
-../lib/standard/bytes.nit:162,6--13: Documentation warning: Undocumented property `to_bytes`
../lib/standard/stream.nit:426,6--17: Documentation warning: Undocumented property `buffer_reset`
../lib/standard/file.nit:455,6--19: Documentation warning: Undocumented property `read_all_bytes`
test_advice_repeated_types.nit:36,15--20: Warning: useless type repetition on redefined attribute `_a`
-Runtime error: Cast failed. Expected `E`, got `Bool` (../lib/standard/collection/array.nit:957)
+Runtime error: Cast failed. Expected `E`, got `Bool` (../lib/standard/collection/array.nit:960)
NativeString
0x4e
Nit