digitalmars.D - [OT] Some neat ideas from the Kotlin language
- Yuxuan Shui (22/22) Feb 18 2016 Just come across Kotlin today, and found some interesting ideas
- Jacob Carlborg (20/40) Feb 19 2016 I think the same applies to Swift. But I think you're supposed to use it...
- Nemanja Boric (12/19) Feb 19 2016 IMHO, without language support looks really bad - `map` really
- Thiez (4/13) Feb 19 2016 I think most would write that as:
- Jacob Carlborg (5/15) Feb 21 2016 You can do the same in Scala, it has built-in pattern matching. Although...
- Nick Sabalausky (7/39) Feb 19 2016 It'd be nice if it didn't require a new variable name though. When I do
- Yuxuan Shui (6/39) Feb 19 2016 The point is, in other languages you would have to explicitly do
- Daniel N (9/16) Feb 20 2016 Swift also has guard, which solves this issue.
- Steven Schveighoffer (4/22) Feb 20 2016 I'm glad you pointed this out, I did not know this. Having to rename
- =?UTF-8?Q?Tobias=20M=C3=BCller?= (13/26) Feb 20 2016 In Rust that would be:
- rsw0x (6/22) Feb 20 2016 D has this too, but only for nullable types afaik.
- =?UTF-8?Q?Tobias=20M=C3=BCller?= (10/42) Feb 22 2016 That's not quite the same as there are no non-nullable pointers in D.
-
rsw0x
(3/28)
Feb 22 2016
Rust's Option
checks are not done at compile-time in most -
Xinok
(6/19)
Feb 23 2016
Option
is an enum type in Rust (i.e. algebraic data type). The - rsw0x (3/23) Feb 23 2016 How does this differ from the example I gave where the branch is
- Xinok (19/22) Feb 23 2016 D doesn't prevent you from dereferencing a null pointer whereas
- Kagamin (13/35) Feb 24 2016 The idea is to match non-null pointers, this is how you do it:
- Andrei Alexandrescu (4/9) Feb 24 2016 Probably we can do the same in a library: never allow the value out of
- Xinok (8/15) Feb 20 2016 I consider this feature similar to requiring all control paths to
- Ice Create Man (4/7) Feb 22 2016 Both those issues predate both Kotlin and Swift. C# has had both
- Yuxuan Shui (7/16) Feb 22 2016 Sure that Optional types and dynamic casts have been there for
- Russel Winder via Digitalmars-d (20/29) Feb 22 2016 But lots of what Kotlin, and Ceylon, are doing are new=E2=80=A6 on the J...
Just come across Kotlin today, and found some interesting ideas skimming through its tutorial: 1) Null check Kotlin has Optional types, suffixed with a '?'. Like 'Int?', same as in Swift. But instead of explicitly unwrapping them (e.g. var! in Swift, or var.unwrap() in Rust), Kotlin let you do this: var: Int? if (var != null) //You can use var here Skipping the null check will get you compile time error. You can even do this: if (var == null) return; //You can use var from now on 2) Smart cast This is a similar to previous one, instead of: var1: Object; var2 = cast(String)var1; You do this: if (var1 is String) //You can use var1 as a String here I think this two ideas are pretty neat, for more information, see: http://kotlinlang.org/docs/reference/typecasts.html
Feb 18 2016
On 2016-02-19 00:33, Yuxuan Shui wrote:Just come across Kotlin today, and found some interesting ideas skimming through its tutorial: 1) Null check Kotlin has Optional types, suffixed with a '?'. Like 'Int?', same as in Swift. But instead of explicitly unwrapping them (e.g. var! in Swift, or var.unwrap() in Rust), Kotlin let you do this: var: Int? if (var != null) //You can use var here Skipping the null check will get you compile time error. You can even do this: if (var == null) return; //You can use var from now onI think the same applies to Swift. But I think you're supposed to use it like this: if let a = var { // a is no unwrapped } I like the way it's used in Scala: val a = Option(value) val b = a.map(e => e /* do something with the unrapped e).getOrElse(/* use a default value here */) The Option type in Scala acts like a zero or one element collection. The Scala way can be implemented in D as well without any language support.2) Smart cast This is a similar to previous one, instead of: var1: Object; var2 = cast(String)var1; You do this: if (var1 is String) //You can use var1 as a String hereIt's similar how it works in D, for Objects: class Foo {} Object foo = new Foo; if (auto o = cast(Foo) foo) // use o as Foo here When casting to a subclass it will return null reference if the cast fails. -- /Jacob Carlborg
Feb 19 2016
On Friday, 19 February 2016 at 12:16:49 UTC, Jacob Carlborg wrote:I like the way it's used in Scala: val a = Option(value) val b = a.map(e => e /* do something with the unrapped e).getOrElse(/* use a default value here */) The Option type in Scala acts like a zero or one element collection. The Scala way can be implemented in D as well without any language support.IMHO, without language support looks really bad - `map` really sticks out here. What Rust is doing: ``` let foo: Option<i32> = bar(); let new_stuff = match foo { Some(x) => x, None => 0 } ``` (or similar, I don't have compiler handy).
Feb 19 2016
On Friday, 19 February 2016 at 12:28:14 UTC, Nemanja Boric wrote:What Rust is doing: ``` let foo: Option<i32> = bar(); let new_stuff = match foo { Some(x) => x, None => 0 } ``` (or similar, I don't have compiler handy).I think most would write that as: let new_stuf = bar().unwrap_or(0); When you use the methods on `Option` you rarely need to match.
Feb 19 2016
On 2016-02-19 13:28, Nemanja Boric wrote:IMHO, without language support looks really bad - `map` really sticks out here. What Rust is doing: ``` let foo: Option<i32> = bar(); let new_stuff = match foo { Some(x) => x, None => 0 } ```You can do the same in Scala, it has built-in pattern matching. Although I think the map approach is preferred, but I'm not a Scala expert. -- /Jacob Carlborg
Feb 21 2016
On 02/19/2016 07:16 AM, Jacob Carlborg wrote:On 2016-02-19 00:33, Yuxuan Shui wrote:Me want.Just come across Kotlin today, and found some interesting ideas skimming through its tutorial: 1) Null check Kotlin has Optional types, suffixed with a '?'. Like 'Int?', same as in Swift. But instead of explicitly unwrapping them (e.g. var! in Swift, or var.unwrap() in Rust), Kotlin let you do this: var: Int? if (var != null) //You can use var hereIt'd be nice if it didn't require a new variable name though. When I do that, I usually find I wind up needing to resort to some hungarian-notation-inspired "start including the type in the variable's name" verbosity. It's a fantastic feature of D, but that Kotlin version seems much nicer.2) Smart cast This is a similar to previous one, instead of: var1: Object; var2 = cast(String)var1; You do this: if (var1 is String) //You can use var1 as a String hereIt's similar how it works in D, for Objects: class Foo {} Object foo = new Foo; if (auto o = cast(Foo) foo) // use o as Foo here When casting to a subclass it will return null reference if the cast fails.
Feb 19 2016
On Friday, 19 February 2016 at 12:16:49 UTC, Jacob Carlborg wrote:On 2016-02-19 00:33, Yuxuan Shui wrote:But you would need to give the unwrapped value a new name.Just come across Kotlin today, and found some interesting ideas skimming through its tutorial: 1) Null check [snip] You can even do this: if (var == null) return; //You can use var from now onI think the same applies to Swift. But I think you're supposed to use it like this: if let a = var { // a is no unwrapped }I like the way it's used in Scala: val a = Option(value) val b = a.map(e => e /* do something with the unrapped e).getOrElse(/* use a default value here */) The Option type in Scala acts like a zero or one element collection. The Scala way can be implemented in D as well without any language support.The point is, in other languages you would have to explicitly do an operation to the wrapped value, but in Kotlin the compiler is able to automatically unwrap it for you when it knows doing so is legal, based on static analysis results.2) Smart cast [snip]It's similar how it works in D, for Objects: class Foo {} Object foo = new Foo; if (auto o = cast(Foo) foo) // use o as Foo here When casting to a subclass it will return null reference if the cast fails.
Feb 19 2016
On Friday, 19 February 2016 at 21:30:37 UTC, Yuxuan Shui wrote:Swift also has guard, which solves this issue. func ex(a: Int?) { // unwrap (possible to add additional check if desired) guard let a = a where a > 0 else { return // fail } a.ok // a is now a plain validated Int }I think the same applies to Swift. But I think you're supposed to use it like this: if let a = var { // a is no unwrapped }But you would need to give the unwrapped value a new name.
Feb 20 2016
On 2/20/16 5:04 AM, Daniel N wrote:On Friday, 19 February 2016 at 21:30:37 UTC, Yuxuan Shui wrote:I'm glad you pointed this out, I did not know this. Having to rename variables all the time is quite annoying. -SteveSwift also has guard, which solves this issue. func ex(a: Int?) { // unwrap (possible to add additional check if desired) guard let a = a where a > 0 else { return // fail } a.ok // a is now a plain validated Int }I think the same applies to Swift. But I think you're supposed to use it like this: if let a = var { // a is no unwrapped }But you would need to give the unwrapped value a new name.
Feb 20 2016
Yuxuan Shui <yshuiv7 gmail.com> wrote:Just come across Kotlin today, and found some interesting ideas skimming through its tutorial: 1) Null check Kotlin has Optional types, suffixed with a '?'. Like 'Int?', same as in Swift. But instead of explicitly unwrapping them (e.g. var! in Swift, or var.unwrap() in Rust), Kotlin let you do this: var: Int? if (var != null) //You can use var hereIn Rust that would be: let var : Option<i32> = ...; if let Some(var) = var { // You can use var here } It works for every enum (= tagged union), not just Option<T> Swift also has "if let". It's not much more verbose but more explicit. Changing the type of a variable based on static analysis is just advanced obfuscation. It hurts readability and the gain is questionable. At least it only works for nullable types. Tobi
Feb 20 2016
On Saturday, 20 February 2016 at 09:40:40 UTC, Tobias Müller wrote:Yuxuan Shui <yshuiv7 gmail.com> wrote:D has this too, but only for nullable types afaik. if(byte* ptr = someFunc()){ //... }[...]In Rust that would be: let var : Option<i32> = ...; if let Some(var) = var { // You can use var here } It works for every enum (= tagged union), not just Option<T> Swift also has "if let". It's not much more verbose but more explicit. Changing the type of a variable based on static analysis is just advanced obfuscation. It hurts readability and the gain is questionable. At least it only works for nullable types. Tobi
Feb 20 2016
rsw0x <anonymous anonymous.com> wrote:On Saturday, 20 February 2016 at 09:40:40 UTC, Tobias Müller wrote:That's not quite the same as there are no non-nullable pointers in D. There's no guarantee from the type system that the byte* is not null and there are no compiler checks involved. It's a simple runtime check. OTOH in the examples in Kotlin/Rust the variable 'var' changes its type from 'int?' to plain 'int'. In Kotlin this is done with static analysis, in Rust with rebinding of the name. TobiYuxuan Shui <yshuiv7 gmail.com> wrote:D has this too, but only for nullable types afaik. if(byte* ptr = someFunc()){ //... }[...]In Rust that would be: let var : Option<i32> = ...; if let Some(var) = var { // You can use var here } It works for every enum (= tagged union), not just Option<T> Swift also has "if let". It's not much more verbose but more explicit. Changing the type of a variable based on static analysis is just advanced obfuscation. It hurts readability and the gain is questionable. At least it only works for nullable types. Tobi
Feb 22 2016
On Tuesday, 23 February 2016 at 06:49:46 UTC, Tobias Müller wrote:rsw0x <anonymous anonymous.com> wrote:Rust's Option<T> checks are not done at compile-time in most cases unless something changed drastically in the past ~18 months.On Saturday, 20 February 2016 at 09:40:40 UTC, Tobias Müller wrote:That's not quite the same as there are no non-nullable pointers in D. There's no guarantee from the type system that the byte* is not null and there are no compiler checks involved. It's a simple runtime check. OTOH in the examples in Kotlin/Rust the variable 'var' changes its type from 'int?' to plain 'int'. In Kotlin this is done with static analysis, in Rust with rebinding of the name. Tobi[...]D has this too, but only for nullable types afaik. if(byte* ptr = someFunc()){ //... }
Feb 22 2016
On Tuesday, 23 February 2016 at 07:18:09 UTC, rsw0x wrote:On Tuesday, 23 February 2016 at 06:49:46 UTC, Tobias Müller wrote:Option<T> is an enum type in Rust (i.e. algebraic data type). The Rust compiler forces you to check all possible cases so you can't use it improperly. So you would have to use something like pattern matching or "if let" to check the state. https://doc.rust-lang.org/book/match.html#matching-on-enumsOTOH in the examples in Kotlin/Rust the variable 'var' changes its type from 'int?' to plain 'int'. In Kotlin this is done with static analysis, in Rust with rebinding of the name. TobiRust's Option<T> checks are not done at compile-time in most cases unless something changed drastically in the past ~18 months.
Feb 23 2016
On Tuesday, 23 February 2016 at 14:58:21 UTC, Xinok wrote:On Tuesday, 23 February 2016 at 07:18:09 UTC, rsw0x wrote:How does this differ from the example I gave where the branch is only taken if the pointer is non-null?On Tuesday, 23 February 2016 at 06:49:46 UTC, Tobias Müller wrote:Option<T> is an enum type in Rust (i.e. algebraic data type). The Rust compiler forces you to check all possible cases so you can't use it improperly. So you would have to use something like pattern matching or "if let" to check the state. https://doc.rust-lang.org/book/match.html#matching-on-enumsOTOH in the examples in Kotlin/Rust the variable 'var' changes its type from 'int?' to plain 'int'. In Kotlin this is done with static analysis, in Rust with rebinding of the name. TobiRust's Option<T> checks are not done at compile-time in most cases unless something changed drastically in the past ~18 months.
Feb 23 2016
On Tuesday, 23 February 2016 at 19:43:43 UTC, rsw0x wrote:... How does this differ from the example I gave where the branch is only taken if the pointer is non-null?D doesn't prevent you from dereferencing a null pointer whereas these scenarios should be impossible in Kotlin as well as Rust. Case and point, this code compiles without issue but crashes at runtime: int* foo() { return null; } void main() { if(int* ptr = new int) { ptr = foo(); // Whoops... *ptr = 35; // Crash } } In D, pointers and reference types can spontaneously become null under almost any context. That's the difference.
Feb 23 2016
On Tuesday, 23 February 2016 at 22:03:32 UTC, Xinok wrote:On Tuesday, 23 February 2016 at 19:43:43 UTC, rsw0x wrote:The idea is to match non-null pointers, this is how you do it: int* foo() { return null; } void main() { if(int* ptr = foo()) { *ptr = 35; // no crash } }... How does this differ from the example I gave where the branch is only taken if the pointer is non-null?D doesn't prevent you from dereferencing a null pointer whereas these scenarios should be impossible in Kotlin as well as Rust. Case and point, this code compiles without issue but crashes at runtime: int* foo() { return null; } void main() { if(int* ptr = new int) { ptr = foo(); // Whoops... *ptr = 35; // Crash } } In D, pointers and reference types can spontaneously become null under almost any context. That's the difference.
Feb 24 2016
On 02/23/2016 09:58 AM, Xinok wrote:Option<T> is an enum type in Rust (i.e. algebraic data type). The Rust compiler forces you to check all possible cases so you can't use it improperly. So you would have to use something like pattern matching or "if let" to check the state. https://doc.rust-lang.org/book/match.html#matching-on-enumsProbably we can do the same in a library: never allow the value out of an Option, but provide a visitor with two aliases (ham/spam). There was a related PR in Phobos, wasn't there? -- Andrei
Feb 24 2016
On Wednesday, 24 February 2016 at 14:50:37 UTC, Andrei Alexandrescu wrote:Probably we can do the same in a library: never allow the value out of an Option, but provide a visitor with two aliases (ham/spam).Rust provides value accessor for Option: https://doc.rust-lang.org/stable/std/option/enum.Option.html#method.unwrap
Feb 25 2016
On Wednesday, 24 February 2016 at 14:50:37 UTC, Andrei Alexandrescu wrote:There was a related PR in Phobos, wasn't there?https://forum.dlang.org/post/n0j9nj$10e9$1 digitalmars.com - probably this.
Feb 25 2016
On my experience programming using Optional's functional interfaces is more reliable then explicit logic, so in case when we have value semantic and Optional then Kotlin's approach is not very useful. My old experiments about this (obviously java-inspired): optional.d import std.typecons; import std.stdio; Nullable!T Optional(T)(){ return Nullable!T(); } Nullable!T Optional(T)(T value){ return Nullable!T(value); } Nullable!OUT map(IN, OUT)(Nullable!IN n, OUT delegate(IN) fn) { return n.isNull() ? Nullable!OUT() : Nullable!OUT(fn(n.get())); } T orElse(T)(Nullable!T n, T value){ return n.isNull() ? value : n.get(); } void ifPresent(T)(Nullable!T n, void delegate(T) fn){ if(!n.isNull()) fn(n.get()); } void ifPresent(T)(Nullable!T n, void function(T) fn){ if(!n.isNull()) fn(n.get()); } bool isPresent(T)(Nullable!T n){ return !n.isNull(); } Nullable!T coalesce(T)(Nullable!T n, Nullable!T other){ return n.isNull() ? other : n; } unittest { assert(Optional!string().isNull()); assert(Optional!string("asd").isPresent()); assert(Optional!string("asd").map((string v) => v~"$") == "asd$"); assert(Optional!string().map((string v) => v~"$").isNull()); assert(Optional!string("true").map((string v) => v=="1" || v=="true").orElse(false) == true); assert(Optional!string().coalesce(Optional!string("test")) == "test"); assert(Optional!string("test1").coalesce(Optional!string("test2")) == "test1"); string a="-"; Optional!string("A").ifPresent((string b){a=b;}); Optional!string().ifPresent((string b){a=b;}); assert(a == "A"); }
Feb 26 2016
On Saturday, 20 February 2016 at 09:40:40 UTC, Tobias Müller wrote:... It's not much more verbose but more explicit. Changing the type of a variable based on static analysis is just advanced obfuscation. It hurts readability and the gain is questionable. At least it only works for nullable types.I consider this feature similar to requiring all control paths to initialize a variable or return a value. Imagine requiring some explicit or verbose syntax to enforce this behavior. I don't see this being an issue as long as the behavior is consistent between compilers (if code works in one compiler, it works in all compilers).
Feb 20 2016
On Thursday, 18 February 2016 at 23:33:45 UTC, Yuxuan Shui wrote:Just come across Kotlin today, and found some interesting ideas skimming through its tutorial: [...]of them for as long as I've been coding in the language. Nothing new here.
Feb 22 2016
On Monday, 22 February 2016 at 19:33:12 UTC, Ice Create Man wrote:On Thursday, 18 February 2016 at 23:33:45 UTC, Yuxuan Shui wrote:Sure that Optional types and dynamic casts have been there for ages. But this is the first time I see a compiler does the unwrapping & casting for you based on static analyses. And Xinok pointed out we have been using the same technique for detecting uninitialized variables, so what Kotlin does can be seen as a small, but clever, extension of this.Just come across Kotlin today, and found some interesting ideas skimming through its tutorial: [...]both of them for as long as I've been coding in the language. Nothing new here.
Feb 22 2016
On Mon, 2016-02-22 at 19:33 +0000, Ice Create Man via Digitalmars-d wrote:On Thursday, 18 February 2016 at 23:33:45 UTC, Yuxuan Shui wrote:But lots of what Kotlin, and Ceylon, are doing are new=E2=80=A6 on the JVM.= I like new, I like progress and evolution. Just because an idea is not objectively new, doesn't mean it isn't new and useful. Context and application can be as refreshing as having a brand new idea. Just think in programming languages today actors, dataflow, CSP are new, despite being 50-ish, and 40-ish years old. =C2=A0 --=20 Russel. =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D Dr Russel Winder t: +44 20 7585 2200 voip: sip:russel.winder ekiga.n= et 41 Buckmaster Road m: +44 7770 465 077 xmpp: russel winder.org.uk London SW11 1EN, UK w: www.russel.org.uk skype: russel_winderJust come across Kotlin today, and found some interesting ideas=C2=A0 skimming through its tutorial: =20 [...]=20 of them for as long as I've been coding in the language. Nothing=C2=A0 new here.
Feb 22 2016