Let's say I define the following interface in a Go library:
type Task interface {
Do() error
}
func Register(task Task) { ... }
func GetId(task Task) int64 { ... }
In Register(), the library associates a unique int64 with each task instance. GetId() must return the identifier for the given task.
My initial idea was to store the association as a map[Task]int64. This seems to work fine, but I was told that it would break if an object implementing Task was not equality-comparable (for example, a struct containing a map). I still need to check if this is true.
I was going to try and use a slice of struct { task Task; id int64 } instead and just iterate over it, but that would still require equality comparable Task instances. And AFAIU there is no identity comparison in Go.
How can I have a robust mapping from Task instances to their ID?
EDIT: Both solutions proposed so far work, but they have the disadvantage that every Task implementation has to include some repetitive code to handle the IDs. I could provide that code in a TaskBase struct that could be embedded, but ideally I would prefer a solution that doesn't require implementations to even know about the IDs (they are internal to the library and have no meaning outside of it).
A more complete example: http://play.golang.org/p/1RzDiw7F9t
package main
import (
"fmt"
"math/rand"
)
type Task interface {
Do() error
ID() int64
}
type XTask struct {
id int64
// other stuff
}
func NewXTask( /*task parameters...*/) *XTask {
t := &XTask{ /*initialize members*/}
t.id = Register(t)
// possibly more initialization...
return t
}
func (t *XTask) Do() error { return nil } // stub
func (t *XTask) ID() int64 { return t.id }
var taskRegistry = map[int64]Task{}
func Register(t Task) int64 {
var id int64
for {
id = rand.Int63()
if _, exists := taskRegistry[id]; !exists {
break
}
}
taskRegistry[id] = t
return id
}
func main() {
t1 := NewXTask()
t2 := NewXTask()
fmt.Printf("%x\n", t1.ID())
fmt.Printf("%x\n", t2.ID())
}
I used an ID method as Daniel suggested, and I turned the map backwards from the way you had it. This is because the Task objects know their own ID, so a map from Task to ID is not needed. A map from ID to task however, is useful for guaranteeing uniqueness. It might come in handy some other time if you find yourself with only an ID and you need the corresponding Task object.
Also note this example is not goroutine-safe. If you need that you will have to add synchronization.
Related
fun viewDidLoad() {
observeViewModel()
initializeUI()
getVideos()
getQuestions()
}
fun initializeUI() {
/*
1 - Create a list as;
VideosTitleRow("Videos"),
VideosBodyRow(null),
QuestionTitleRow("Questions"),
QuestionsBodyRow(null),
...."
Note: The bodies are null right now. There will fill with correct values after.
---
2 - Call updateUI functions for update ui with initialize list.
*/
}
fun getVideos() {
viewModel.getVideos()
}
fun getQuestions() {
viewModel.getQuestions()
}
fun observeViewModel() {
// Videos
CoroutineScope(Dispatchers.IO).launch {
when (flow) {
// ...
is VideosFlow.DataReceived -> {
val row = SectionVideosBodyData(flow.videos)
updateUI(1, row)
}
}
}
// Questions
CoroutineScope(Dispatchers.IO).launch {
when (flow) {
// ...
is QuestionsFlow.DataReceived -> {
val row = SectionQuestionsBodyData(flow.questions)
updateUI(3, row)
}
}
}
// And others LiveDatas under observing ....
}
fun updateUI(indexAt: Int? = null, row: BaseAdapterData = null) {
/*
If indexAt and row parameters are not null;
edit the global row list then created new row list from this (global list) and send the new list to adapter for update ui.
If parameters are null; send the global list to adapter for update ui.
*/
}
This is the current structure.
Let me try to explain what is problem;
When i start the initializeUI() function i know when it will finish the job. Because this is a synchronous function.
getVideos() or getQuestions() functions are a synchronous functions too but they start to api call, send request, take response, convert to ui model, bla bla operations. And we have to observe the results. So, we don't know when this job will finish!
getVideos() function just like says to viewModel.getVideos; "Let me know when you see the red car" but we can't know when is the red car pass on street.
In this case; although getQuestions() function is called before getVideos(), it may finish before it. In fact, both can end at the same time.
Here is i need;
I want to use kotlin coroutines scopes in getVideos(), getQuestions(), ... functions run as asynchronous but every job must wait for finished updateUI() function.
1- initializeUI() function runs, create a list, send to adapter, update the ui,
2- getVideos() or getQuestions() runs as asynchronous,
let say; livedata(getVideos) finish the their work but livedata (getQuestions) still working.
getQuestion() when call the updateUI() function, getVideos() can not call until updateUI() function finished called from getQuestion()
I know this is a complicated case :)
But the LiveData is messing up my mind.
I tried Mutex but although getVideos() or getQuestions() functions are synchronous, they starts an asynchronous job.
(Kotlin Coroutines sequential execution)
I have a problem to understand why the address operator can be used when the return type is an interface
func NewReader() IReader {
return &Reader{}
}
but (of course) not when a return type is a struct
func NewReader() Reader {
return &Reader{} // cannot use &Reader literal (type *Reader) as type Reader in return argument
}
The function signature later is func MyFuncReader(r IReader) but the reflect.TypeOf(r) is *main.Reader.
So the type IReader is hiding the fact that it is pointer?
The function signature func MyFuncReader(r IReader) doesn't tell me, that a pointer or a value was passed the func?
Samples
Full Sample with interface https://play.golang.org/p/1Db1Jybp0rP
Full Sample without interface https://play.golang.org/p/nPtu09yhe0C
If the return type of a function is an interface type, you may return any values that implement that interface. Spec: Return statements:
The return value or values may be explicitly listed in the "return" statement. Each expression must be single-valued and assignable to the corresponding element of the function's result type.
In your first example Reader has methods with pointer receiver, so only a pointer to Reader (that is *Reader) implements the IReader interface. So you have to return &Reader{}.
If your function has a return type of a concrete type, you have to return a value of that exact concrete type, you can't return a value of a pointer to that type.
When the return type is a Reader
func NewReader() Reader {
return &Reader{} // cannot use &Reader literal (type *Reader) as type Reader in return argument
}
you cannot use a pointer to a Reader type in place of a Reader type. The reason being they are just not of the same type.
When you use an interface like IReader as a return type as in
func NewReader() IReader {
return &Reader{}
}
it basically means that any type implementing the methods of the IReader interface will classify as a type implementing that interface and thus will be acceptable. Since the type *Reader implements the IReader type in your example, it is an acceptable return value of the NewReader function here. That means if I introduce a new type which implements this interface, such as,
type dummy int
func (d dummy) GetCount() int {
return d
}
func (d dummy) IncreaseCount() {
fmt.Println("Increased count: %d", d)
}
then I can do something like
func NewReader() IReader {
var d dummy
d = 5
return d
}
and it would still work. The underlying type of this returned value on checking using the reflect package will be dummy.
I have a tool that I'm writing that exposes some functions that pull information out of a static database to several scripting languages that I'm embedding into the tool.
I thought; "Hey sounds like a nice use case for interfaces". So I defined an interface like so in my package scripting
type ScriptingLang interface {
RunScript(filename string) error
RunString(s string) error
Interpreter() error
Init() error
IsInit() bool
}
Then I store a map of them so I can look them up by a string defined like so in a different package.
var ScriptingLangs = make(map[string]scripting.ScriptingLang)
and a function to register them. Also some little helper functions like
func RunString(lang, s string) error {
if v, ok := ScriptingLangs[lang]; ok {
if !v.IsInit() {
v.Init()
}
return v.RunString(s)
} else {
return NoSuchLangErr
}
return nil
}
The problem that I ran into is it seams that interfaces can't have methods with pointer receivers. As a result my Lua struct that implements ScriptingLang isn't able to save it's *state because it's stored in ScriptingLangs.
I've tried updating the value stored in the map at the end of functions that save state and it didn't update the value.
To my understanding you shouldn't use pointers of interfaces so what are my options here? I would like to really keep the interfaces so I can do some neat stuff with git submodules.
A minimal example of my problem:
package main
import (
"fmt"
)
type ScriptingLang interface {
DoString(s string) error
Init() error
}
type Lua struct {
state string
}
func (l Lua) DoString(s string) error {
fmt.Printf("Doing '%v' with state '%v'\n", s, l.state)
return nil
}
func (l Lua) Init() error {
l.state = "Inited"
return nil
}
var lang ScriptingLang
func main() {
lang = Lua{}
lang.Init()
lang.DoString("Stuff")
}
If you want to mutate state, you need a pointer receiver, and your Init method doesn't have one. The fact that you're storing the value inside an interface makes no difference.
In your minimal(-ish) example, change the Init method (and any method that updates state) to have a pointer receiver, and point a pointer inside the interface and everything works:
func (l *Lua) Init() error {
l.state = "Inited"
return nil
}
...
func main() {
lang = &Lua{}
lang.Init()
lang.DoString("Stuff")
}
This article might help: http://jordanorelli.com/post/32665860244/how-to-use-interfaces-in-go
Right now I have code that uses the rusqlite sqlite bindings to open a db connection and do a bunch of db operations in my application like this:
extern crate rusqlite;
use rusqlite::SqliteConnection;
struct MyAppState {
db: SqliteConnection,
// ... pretend there's other fields here ...
}
impl MyAppState {
fn new() -> MyAppState {
let db = SqliteConnection::open(":memory:").unwrap();
MyAppState {
db: db
}
}
fn query_some_info(&mut self, arg: i64) -> i64 {
let mut stmt = self.db.prepare("SELECT ? + 1").unwrap();
let mut result_iter = stmt.query(&[&arg]).unwrap();
let result = result_iter.next().unwrap().unwrap().get(0);
result
}
}
fn main() {
let mut app = MyAppState::new();
for i in range(0, 100) {
let result = app.query_some_info(i);
println!("{}", result);
}
}
Since the prepared statement lives in a local variable, this seems to miss the point of prepared statements to some extent since I have to re-prepare it every time the function is called and the local variable comes into being. Ideally, I would prepare all my statements at most once and stash them in the MyAppState struct for the duration of the db connection.
However, since the SqliteStatement type is parameterized over the lifetime of the db connection, it borrows the connection and by extension the struct it lives in and I can't do anything with the struct anymore like return the struct by value or call &mut self methods on it (query_some_info doesn't really need to take &mut self here, but some code in my actual program does unless everything goes on to live in RefCells, which isn't the worst, I guess, but still).
Usually when the borrow checker betrays me like that, my recourse is to give up on stack discipline and put some Rc<RefCell< >> here and there until it all works out, but in this case there's some lifetimes in the types either way and I don't know how to word it in a way that appeases the borrow checker.
Ideally I'd like to write code that only prepares the statements right when the db gets opened, or maybe prepares them only once when they are first used, and then never calls prepare again during the duration of the db connection, while mostly keeping the safety of the rusqlite bindings rather than writing code against the sqlite3 C API or breaking abstraction or whatever. How do I?
You are right, indeed, that sibling references are awkward in Rust. There is a good reason though, they are not easily modeled by the ownership system.
In this particular case, I would advise you to split the structure: you can keep the prepared statements in a dedicated cache also parametrized on the lifetime of the db for example; the db instead should be instantiated at the top of your program and passed down (think dependency injection) so that the cache that depends on it can outlive the program main function.
This does mean that the db will remain borrowed, obviously.
The Statement struct has a lifetime parameter, Statement<'conn>. When you prepare the statement, you must have a reference to the Connection that outlives the statement.
extern crate rusqlite;
use rusqlite::{Connection, Statement};
struct MyAppState {
db: Connection,
}
impl MyAppState {
fn new() -> MyAppState {
let db = Connection::open(":memory:").unwrap();
MyAppState { db: db }
}
}
struct PreparedStatement<'conn> {
statement: Statement<'conn>,
}
impl<'conn> PreparedStatement<'conn> {
pub fn new<'a>(conn: &'a Connection, sql: &str) -> PreparedStatement<'a> {
PreparedStatement {
statement: conn.prepare(sql).unwrap(),
}
}
fn query_some_info(&mut self, arg: i64) -> i64 {
let mut result_iter = self.statement.query(&[&arg]).unwrap();
let result = result_iter.next().unwrap().unwrap().get(0);
result
}
}
fn main() {
let app = MyAppState::new();
let mut prepared_stmt = PreparedStatement::new(&app.db, "SELECT ? + 1");
for i in 0..100 {
let result = prepared_stmt.query_some_info(i);
println!("{}", result);
}
}
In Rust, unlike some other languages, I have found that factoring something out into a function changes its meaning. It introduces new lifetimes, which usually works against you. But in this case, that's exactly what was needed.
is it possible to create your own futures in Dart to return from your methods, or must you always return a built in future return from one of the dart async libraries methods?
I want to define a function which always returns a Future<List<Base>> whether its actually doing an async call (file read/ajax/etc) or just getting a local variable, as below:
List<Base> aListOfItems = ...;
Future<List<Base>> GetItemList(){
return new Future(aListOfItems);
}
If you need to create a future, you can use a Completer. See Completer class in the docs. Here is an example:
Future<List<Base>> GetItemList(){
var completer = new Completer<List<Base>>();
// At some time you need to complete the future:
completer.complete(new List<Base>());
return completer.future;
}
But most of the time you don't need to create a future with a completer. Like in this case:
Future<List<Base>> GetItemList(){
var completer = new Completer();
aFuture.then((a) {
// At some time you need to complete the future:
completer.complete(a);
});
return completer.future;
}
The code can become very complicated using completers. You can simply use the following instead, because then() returns a Future, too:
Future<List<Base>> GetItemList(){
return aFuture.then((a) {
// Do something..
});
}
Or an example for file io:
Future<List<String>> readCommaSeperatedList(file){
return file.readAsString().then((text) => text.split(','));
}
See this blog post for more tips.
You can simply use the Future<T>value factory constructor:
return Future<String>.value('Back to the future!');
Returning a future from your own function
This answer is a summary of the many ways you can do it.
Starting point
Your method could be anything but for the sake of these examples, let's say your method is the following:
int cubed(int a) {
return a * a * a;
}
Currently you can use your method like so:
int myCubedInt = cubed(3); // 27
However, you want your method to return a Future like this:
Future<int> myFutureCubedInt = cubed(3);
Or to be able to use it more practically like this:
int myCubedInt = await cubed(3);
The following solutions all show ways to do that.
Solution 1: Future() constructor
The most basic solution is to use the generative constructor of Future.
Future<int> cubed(int a) {
return Future(() => a * a * a);
}
I changed the return type of the method to Future<int> and then passed in the work of the old function as an anonymous function to the Future constructor.
Solution 2: Future named constructor
Futures can complete with either a value or an error. Thus if you want to specify either of these options explicitly you can use the Future.value or Future.error named constructors.
Future<int> cubed(int a) {
if (a < 0) {
return Future.error(ArgumentError("'a' must be positive."));
}
return Future.value(a * a * a);
}
Not allowing a negative value for a is a contrived example to show the use of the Future.error constructor. If there is nothing that would produce an error then you can simply use the Future.value constructor like so:
Future<int> cubed(int a) {
return Future.value(a * a * a);
}
Solution 3: async method
An async method automatically returns a Future so you can just mark the method async and change the return type like so:
Future<int> cubed(int a) async {
return a * a * a;
}
Normally you use async in combination with await, but there is nothing that says you must do that. Dart automatically converts the return value to a Future.
In the case that you are using another API that returns a Future within the body of your function, you can use await like so:
Future<int> cubed(int a) async {
return await cubedOnRemoteServer(a);
}
Or this is the same thing using the Future.then syntax:
Future<int> cubed(int a) async {
return cubedOnRemoteServer(a).then((result) => result);
}
Solution 4: Completer
Using a Completer is the most low level solution. You only need to do this if you have some complex logic that the solutions above won't cover.
import 'dart:async';
Future<int> cubed(int a) async {
final completer = Completer();
if (a < 0) {
completer.completeError(ArgumentError("'a' must be positive."));
} else {
completer.complete(a * a * a);
}
return completer.future;
}
This example is similar to the named constructor solution above. It handles errors in addition completing the future in the normal way.
A note about blocking the UI
There is nothing about using a future that guarantees you won't block the UI (that is, the main isolate). Returning a future from your function simply tells Dart to schedule the task at the end of the event queue. If that task is intensive, it will still block the UI when the event loop schedules it to run.
If you have an intensive task that you want to run on another isolate, then you must spawn a new isolate to run it on. When the task completes on the other isolate, it will return a message as a future, which you can pass on as the result of your function.
Many of the standard Dart IO classes (like File or HttpClient) have methods that delegate the work to the system and thus don't do their intensive work on your UI thread. So the futures that these methods return are safe from blocking your UI.
See also
Asynchrony support documentation
Flutter Future vs Completer
#Fox32 has the correct answer addition to that we need to mention Type of the Completer otherwise we get exception
Exception received is type 'Future<dynamic>' is not a subtype of type 'FutureOr<List<Base>>
so initialisation of completer would become
var completer= new Completer<List<Base>>();
Not exactly the answer for the given question, but sometimes we might want to await a closure:
flagImage ??= await () async {
...
final image = (await codec.getNextFrame()).image;
return image;
}();
I think it does create a future implicitly, even though we don't pass it anywhere.
Here a simple conditional Future example.
String? _data;
Future<String> load() async {
// use preloaded data
if (_data != null) return Future<String>.value(_data);
// load data only once
String data = await rootBundle.loadString('path_to_file');
_data = data;
return data;
}