I have code that declares a mutable dictionary but I will get an error when I try to change an element.
The code:
let layers =
seq {
if recipes.ContainsKey(PositionSide.Short) then yield! buildLayerSide recipes.[PositionSide.Short]
if recipes.ContainsKey(PositionSide.Long) then yield! buildLayerSide recipes.[PositionSide.Long]
}
|> Seq.map (fun l -> l.Id, l)
|> dict
this creates an IDictionary. I understand that the object itself is immutable but the contents of the dictionary should be mutable.
When I change the code by explicitly initializing the dictionary then it becomes mutable:
let layers =
let a =
seq {
if recipes.ContainsKey(PositionSide.Short) then yield! buildLayerSide recipes.[PositionSide.Short]
if recipes.ContainsKey(PositionSide.Long) then yield! buildLayerSide recipes.[PositionSide.Long]
}
|> Seq.map (fun l -> l.Id, l)
|> dict
let x = Dictionary<string, Layer>()
a
|> Seq.iter (fun kvp -> x.[kvp.Key] <- kvp.Value)
x
Why is that?
IDictionary is an interface, not a class. This interface may have multiple different implementations. You can even make one yourself.
Dictionary is indeed one of these implementations. It supports the full functionality of the interface.
But that's not the implementation that the dict function returns. Let's try this:
> let d = dict [(1,2)]
> d.GetType().FullName
"Microsoft.FSharp.Core.ExtraTopLevelOperators+DictImpl`3[...
Turns out the implementation that the dict function returns is Microsoft.FSharp.Core.ExtraTopLevelOperators.DictImpl - a class named DictImpl defined deep in the innards of the F# standard library.
And it just so happens that certain methods on that interface throw a NotSupportedException:
> d.Add(4,5)
System.NotSupportedException: This value cannot be mutated
That's by design. It's done this way on purpose, to support "immutability by default".
If you really want to have a mutable version, you can create a copy by using one of Dictionary's constructors:
> let m = Dictionary(d)
> m.Add(4,5) // Works now
The difference between Map and Dictionary is the implementation, which then implies memory and runtime characteristics.
Dictionary is a hashtable. It offers constant-time insertion and retrieval, but to pay for that it relies on consistent hashing of its keys and its updates are destructive, which also comes with thread-unsafety.
Map is implemented as a tree. It offers logarithmic insertion and retrieval, but in return has the benefits of a persistent data structure. Also, it requires keys to be comparable. Try this:
> type Foo() = class end
> let m = Map [(Foo(), "bar")]
error FS0001: The type 'Foo' does not support the 'comparison' constraint
Comparing keys is essential for building a tree.
The difference is that dict is a read-only dictionary with some mutating methods that throw an exception (which is a disadvantage of that type), whereas the map is an immutable collection that uses functions from the Map module as well as methods to modify elements of the map and return a copy. There is a good explanation of this in Lesson 17 of the book Get Programming with F#.
Also, for the dict, "Retrieving a value by using its key is very fast, close to O(1), because the Dictionary class is implemented as a hash table." from the docs; whereas the map is based on a binary tree, so retrieving a value by using its key has O(log(N)) complexity. See Collection Types. This also means that the keys in a map are ordered; whereas in a dict, they are unordered.
For many use cases, the difference in performance would be negligible, so the default choice for Functional Programming style should be the map, since its programming interface is similar in style to the other F# collections like list and seq.
dict is a helper method to create an iDictionary, this dictionary is immutable (so you need to supply the contents during the creation of the object). It is actually a read-only dictionary so no surprise that you cannot modify its contents. In your second example you explicitly create a Dictionary which is a mutable dictionary. Since Dictionary can take a iDictionary you could just pass in your iDictionary to it.
Related
I am trying to create a user input validation function in rust utilising functional programming and recursion. How can I return an immutable vector with one element concatenated onto the end?
fn get_user_input(output_vec: Vec<String>) -> Vec<String> {
// Some code that has two variables: repeat(bool) and new_element(String)
if !repeat {
return output_vec.add_to_end(new_element); // What function could "add_to_end" be?
}
get_user_input(output_vec.add_to_end(new_element)) // What function could "add_to_end" be?
}
There are functions for everything else:
push adds a mutable vector to a mutable vector
append adds an element to the end of a mutable vector
concat adds an immutable vector to an immutable vector
??? adds an element to the end of a immutable vector
The only solution I have been able to get working is using:
[write_data, vec![new_element]].concat()
but this seems inefficient as I'm making a new vector for just one element (so the size is known at compile time).
You are confusing Rust with a language where you only ever have references to objects. In Rust, code can have exclusive ownership of objects, and so you don't need to be as careful about mutating an object that could be shared, because you know whether or not the object is shared.
For example, this is valid JavaScript code:
const a = [];
a.push(1);
This works because a does not contain an array, it contains a reference to an array.1 The const prevents a from being repointed to a different object, but it does not make the array itself immutable.
So, in these kinds of languages, pure functional programming tries to avoid mutating any state whatsoever, such as pushing an item onto an array that is taken as an argument:
function add_element(arr) {
arr.push(1); // Bad! We mutated the array we have a reference to!
}
Instead, we do things like this:
function add_element(arr) {
return [...arr, 1]; // Good! We leave the original data alone.
}
What you have in Rust, given your function signature, is a totally different scenario! In your case, output_vec is owned by the function itself, and no other entity in the program has access to it. There is therefore no reason to avoid mutating it, if that is your goal:
fn get_user_input(mut output_vec: Vec<String>) -> Vec<String> {
// Add mut ^^^
You have to keep in mind that any non-reference is an owned value. &Vec<String> would be an immutable reference to a vector something else owns, but Vec<String> is a vector this code owns and nobody else has access to.
Don't believe me? Here's a simple example of broken code that demonstrates this:
fn take_my_vec(y: Vec<String>) { }
fn main() {
let mut x = Vec::<String>::new();
x.push("foo".to_string());
take_my_vec(x);
println!("{}", x.len()); // E0382
}
The expression x.len() causes a compile-time error, because the vector x was moved into the function argument and we don't own it anymore.
So why shouldn't the function mutate the vector it owns now? The caller can't use it anymore.
In summary, functional programming looks a bit different in Rust. In other languages that have no way to communicate "I'm giving you this object" you must avoid mutating values you are given because the caller may not expect you to change them. In Rust, who owns a value is clear, and the argument reflects that:
Is the argument a value (Vec<String>)? The function owns the value now, the caller gave it away and can't use it anymore. Mutate it if you need to.
Is the argument an immutable reference (&Vec<String>)? The function doesn't own it, and it can't mutate it anyway because Rust won't allow it. You could clone it and mutate the clone.
Is the argument a mutable reference (&mut Vec<String>)? The caller must explicitly give the function a mutable reference and is therefore giving the function permission to mutate it -- but the function still doesn't own the value. The function can mutate it, clone it, or both -- it depends what the function is supposed to do.
If you take an argument by value, there is very little reason not to make it mut if you need to change it for whatever reason. Note that this detail (mutability of function arguments) isn't even part of the function's public signature simply because it's not the caller's business. They gave the object away.
Note that with types that have type arguments (like Vec) other expressions of ownership are possible. Here are a few examples (this is not an exhaustive list):
Vec<&String>: You now own a vector, but you don't own the String objects that it contains references to.
&Vec<&String>: You are given read-only access to a vector of string references. You could clone this vector, but you still couldn't change the strings, just rearrange them, for example.
&Vec<&mut String>: You are given read-only access to a vector of mutable string references. You can't rearrange the strings, but you can change the strings themselves.
&mut Vec<&String>: Like the above but opposite: you are allowed to rearrange the string references but you can't change the strings.
1 A good way to think of it is that non-primitive values in JavaScript are always a value of Rc<RefCell<T>>, so you're passing around a handle to the object with interior mutability. const only makes the Rc<> immutable.
Looking through the documentation for std::cell::Cell, I don't see anywhere how I can retrieve a non-mutable reference to inner data. There is only the get_mut method: https://doc.rust-lang.org/std/cell/struct.Cell.html#method.get_mut
I don't want to use this function because I want to have &self instead of &self mut.
I found an alternative solution of taking the raw pointer:
use std::cell::Cell;
struct DbObject {
key: Cell<String>,
data: String
}
impl DbObject {
pub fn new(data: String) -> Self {
Self {
key: Cell::new("some_uuid".into()),
data,
}
}
pub fn assert_key(&self) -> &str {
// setup key in the future if is empty...
let key = self.key.as_ptr();
unsafe {
let inner = key.as_ref().unwrap();
return inner;
}
}
}
fn main() {
let obj = DbObject::new("some data...".into());
let key = obj.assert_key();
println!("Key: {}", key);
}
Is there any way to do this without using unsafe? If not, perhaps RefCell will be more practical here?
Thank you for help!
First of, if you have a &mut T, you can trivially get a &T out of it. So you can use get_mut to get &T.
But to get a &mut T from a Cell<T> you need that cell to be mutable, as get_mut takes a &mut self parameter. And this is by design the only way to get a reference to the inner object of a cell.
By requiring the use of a &mut self method to get a reference out of a cell, you make it possible to check for exclusive access at compile time with the borrow checker. Remember that a cell enables interior mutability, and has a method set(&self, val: T), that is, a method that can modify the value of a non-mut binding! If there was a get(&self) -> &T method, the borrow checker could not ensure that you do not hold a reference to the inner object while setting the object, which would not be safe.
TL;DR: By design, you can't get a &T out of a non-mut Cell<T>. Use get_mut (which requires a mut cell), or set/replace (which work on a non-mut cell). If this is not acceptable, then consider using RefCell, which can get you a &T out of a non-mut instance, at some runtime cost.
In addition to to #mcarton answer, in order to keep interior mutability sound, that is, disallow mutable reference to coexist with other references, we have three different ways:
Using unsafe with the possibility of Undefined Behavior. This is what UnsafeCell does.
Have some runtime checks, involving runtime overhead. This is the approach RefCell, RwLock and Mutex use.
Restrict the operations that can be done with the abstraction. This is what Cell, Atomic* and (the unstable) OnceCell (and thus Lazy that uses it) does (note that the thread-safe types also have runtime overhead because they need to provide some sort of locking). Each provides a different set of allowed operations:
Cell and Atomic* do not let you to get a reference to the contained value, and only replace it as whole (basically, get() and set, though convenience methods are provided on top of these, such as swap()). Projection (cell-of-slice to slice-of-cells) is also available for Cell (field projection is possible, but not provided as part of std).
OnceCell allows you to assign only once and only then take shared reference, guaranteeing that when you assign you have no references and while you have shared references you cannot assign anymore.
Thus, when you need to be able to take a reference into the content, you cannot choose Cell as it was not designed for that - the obvious choice is RefCell, indeed.
I'm experimenting with the reflection functionality in Kotlin, but I can't seem to understand how to obtain a KType value.
Suppose I have a class that maps phrases to object factories. In case of ambiguity, the user can supply a type parameter that narrows the search to only factories that return that type of object (or some sub-type).
fun mapToFactory(phrase: Phrase,
type: KType = Any::class): Any {...}
type needs to accept just about anything, including Int, which from my experience seems to be treated somewhat specially. By default, it should be something like Any, which means "do not exclude any factories".
How do I assign a default value (or any value) to type?
From your description, sounds like your function should take a KClass parameter, not a KType, and check the incoming objects with isSubclass, not isSubtype.
Types (represented by KType in kotlin-reflect) usually come from signatures of declarations in your code; they denote a broad set of values which functions take as parameters or return. A type consists of the class, generic arguments to that class, and nullability. The problem with types at runtime on JVM is that because of erasure, it's impossible to determine the exact type of a variable of a generic class. For example if you have a list, you cannot determine the generic type of that list at runtime, i.e. you cannot differentiate between List<String> and List<Throwable>.
To answer your initial question though, you can create a KType out of a KClass with createType():
val type: KType = Any::class.createType()
Note that if the class is generic, you need to pass type projections of generic arguments. In simple cases (all type variables can be replaced with star projections), starProjectedType will also work. For more info on createType and starProjectedType, see this answer.
Since Kotlin 1.3.40, you can use the experimental function typeOf<T>() to obtain the KType of any type:
val int: KType = typeOf<Int>()
In contrast to T::class.createType(), this supports nested generic arguments:
val listOfString: KType = typeOf<List<String>>()
The typeOf<T>() function is particularly useful when you want to obtain a KType from a reified type parameter:
inline fun <reified T> printType() {
val type = typeOf<T>()
println(type.toString())
}
Example usage:
fun main(args: Array<String>) {
printType<Map<Int, String>>()
// prints: kotlin.collections.Map<kotlin.Int, kotlin.String>
}
Since this feature is still in experimental status, you need to opt-in with #UseExperimental(ExperimentalStdlibApi::class) around your function that uses typeOf<T>(). As the feature becomes more stable (possibly in Kotlin 1.4), this can be omitted. Also, at this time it is only available for Kotlin/JVM, not Kotlin/Native or Kotlin/JS.
See also:
Release announcement
API Doc (very sparse currently)
Ceylon has several different concepts for things that might all be considered some kind of array: List, Tuple, Sequence, Sequential, Iterable, Array, Collection, Category, etc. What's is different about these these types and when should I use them?
The best place to start to learn about these things at a basic level is the Ceylon tour. And the place to learn about these things in depth is the module API. It can also be helpful to look at the source files for these.
Like all good modern programming languages, the first few interfaces are super abstract. They are built around one formal member and provide their functionality through a bunch of default and actual members. (In programming languages created before Java 8, you may have heard these called "traits" to distinguish them from traditional interfaces which have only formal members and no functionality.)
Category
Let's start by talking about the interface Category. It represents types of which you can ask "does this collection contain this object", but you may not necessarily be able to get any of the members out of the collection. It's formal member is:
shared formal Boolean contains(Element element)
An example might be the set of all the factors of a large number—you can efficiently test if any integer is a factor, but not efficiently get all the factors.
Iterable
A subtype of Category is the interface Iterable. It represents types from which you can get each element one at a time, but not necessarily index the elements. The elements may not have a well-defined order. The elements may not even exist yet but are generated on the fly. The collection may even be infinitely long! It's formal member is:
shared formal Iterator<Element> iterator()
An example would be a stream of characters like standard out. Another example would be a range of integers provided to a for loop, for which it is more memory efficient to generate the numbers one at a time.
This is a special type in Ceylon and can be abbreviated {Element*} or {Element+} depending on if the iterable might be empty or is definitely not empty, respectively.
Collection
One of Iterable's subtypes is the interface Collection. It has one formal member:
shared formal Collection<Element> clone()
But that doesn't really matter. The important thing that defines a Collection is this line in the documentation:
All Collections are required to support a well-defined notion of value
equality, but the definition of equality depends upon the kind of
collection.
Basically, a Collection is a collection who structure is well-defined enough to be equatable to each other and clonable. This requirement for a well-defined structure means that this is the last of the super abstract interfaces, and the rest are going to look like more familiar collections.
List
One of Collection's subtypes is the interface List. It represents a collection whose elements we can get by index (myList[42]). Use this type when your function requires an array to get things out of, but doesn't care if it is mutable or immutable. It has a few formal methods, but the important one comes from its other supertype Correspondence:
shared formal Item? get(Integer key)
Sequential, Sequence, Empty
The most important of List's subtypes is the interface Sequential. It represents an immutable List. Ceylon loves this type and builds a lot of syntax around it. It is known as [Element*] and Element[]. It has exactly two subtypes:
Empty (aka []), which represents empty collections
Sequence (aka [Element+]), which represents nonempty collections.
Because the collections are immutable, there are lots of things you can do with them that you can't do with mutable collections. For one, numerous operations can fail with null on empty lists, like reduce and first, but if you first test that the type is Sequence then you can guarantee these operations will always succeed because the collection can't become empty later (they're immutable after all).
Tuple
A very special subtype of Sequence is Tuple, the first true class listed here. Unlike Sequence, where all the elements are constrained to one type Element, a Tuple has a type for each element. It gets special syntax in Ceylon, where [String, Integer, String] is an immutable list of exactly three elements with exactly those types in exactly that order.
Array
Another subtype of List is Array, also a true class. This is the familiar Java array, a mutable fixed-size list of elements.
drhagen has already answered the first part of your question very well, so I’m just going to say a bit on the second part: when do you use which type?
In general: when writing a function, make it accept the most general type that supports the operations you need. So far, so obvious.
Category is very abstract and rarely useful.
Iterable should be used if you expect some stream of elements which you’re just going to iterate over (or use stream operations like filter, map, etc.).
Another thing to consider about Iterable is that it has some extra syntax sugar in named arguments:
void printAll({Anything*} things, String prefix = "") {
for (thing in things) {
print(prefix + (thing?.string else "<null>"));
}
}
printAll { "a", "b", "c" };
printAll { prefix = "X"; "a", "b", "c" };
Try online
Any parameter of type Iterable can be supplied as a list of comma-separated arguments at the end of a named argument list. That is,
printAll { "a", "b", "c" };
is equivalent to
printAll { things = { "a", "b", "c" }; };
This allows you to craft DSL-style expressions; the tour has some nice examples.
Collection is, like Correspondence, fairly abstract and in my experience rarely used directly.
List sounds like it should be a often used type, but actually I don’t recall using it a lot. I’m not sure why. I seem to skip over it and declare my parameters as either Iterable or Sequential.
Sequential and Sequence are when you want an immutable, fixed-length list. It also has some syntax sugar: variadic methods like void foo(String* bar) are a shortcut for a Sequential or Sequence parameter. Sequential also allows you to do use the nonempty operator, which often works out nicely in combination with first and rest:
String commaSeparated(String[] strings) {
if (nonempty strings) {
value sb = StringBuilder();
sb.append(strings.first); // known to exist
for (string in strings.rest) { // skip the first one
sb.append(", ").append(string);
// we don’t need a separate boolean to track if we need the comma or not :)
}
return sb.string;
} else {
return "";
}
}
Try online
I usually use Sequential and Sequence when I’m going to iterate over a stream several times (which could be expensive for a generic Iterable), though List might be the better interface for that.
Tuple should never be used as Tuple (except in the rare case where you’re abstracting over them), but with the [X, Y, Z] syntax sugar it’s often useful. You can often refine a Sequential member to a Tuple in a subclass, e. g. the superclass has a <String|Integer>[] elements which in one subclass is known to be a [String, Integer] elements.
Array I’ve never used as a parameter type, only rarely as a class to instantiate and use.
Forgive me if this question seems stupid, but I'm quite new to the whole world of functional programming so I'll need some denizens on StackOverflow to set me straight.
From what I gather, an operation on a monad returns a monad. Does this mean that monads have a fluent interface, whereby each function that is applied on a monad returns that monad after it applies some operation to the variable it wraps?
Presumably you're referring to the bind operator associated with monads, wherein one can start with a monadic value, bind it to a monadic function, and wind up with another monadic value. That's a lot like a "fluent method" (or a set of such making up a "fluent interface") that returns a "this" pointer or reference, yes, but what you'd be missing out on there is that the monadic function need not return a monadic value that's the same type as the input value. The fluent method convention is to return the same type of value so as to continue chaining calls that are all valid on the instance (or instances) being prepared.
The monadic bind operator signature looks more like this:
M[a] -> (a -> M[b]) -> M[b]
That is, the "return value" is possibly of a type different from to the first input value's type. It's only the same when the provided function has the type
(a -> M[a])
It all depends on the type of the monadic function—and, more specifically, the return type of the monadic function.
If you were to constrain the domain of the monadic functions you'd accept to those that return the same type as the monadic value supplied to the bind operator, then yes, you'd have something that behaves like a fluent interface.
Based on what I know about fluent interfaces, they are mostly about making the code "read nicely" by using method chaining. So for example:
Date date = date()
.withYear(2008)
.withMonth(Calendar.JANUARY)
.withDayOfMonth(15)
.toDate();
A Haskell do-notation version of it (using an imaginary date api) could look like:
do date
withYear 2008
withMonth JANUARY
withDayOfMonth 15
toDate
Whether or not this or other do-notation based DSLs like it qualify as a "fluent interface" is probably up for discussion, since there is no formal definition of what a "fluent interface" is. I'd say if it reads like this then it's close enough.
Note that this isn't exactly specific to monads; monads CAN have a fluent interface if you don't require method calling, but that would depend on the function names and the way the API is used.