{"action":"created","issue":{"url":"https://api.github.com/repos/INRIA/spoon/issues/1070","repository_url":"https://api.github.com/repos/INRIA/spoon","labels_url":"https://api.github.com/repos/INRIA/spoon/issues/1070/labels{/name}","comments_url":"https://api.github.com/repos/INRIA/spoon/issues/1070/comments","events_url":"https://api.github.com/repos/INRIA/spoon/issues/1070/events","html_url":"https://github.com/INRIA/spoon/issues/1070","id":197137547,"number":1070,"title":"feature: all you want for queries","user":{"login":"pvojtechovsky","id":23107345,"avatar_url":"https://avatars.githubusercontent.com/u/23107345?v=3","gravatar_id":"","url":"https://api.github.com/users/pvojtechovsky","html_url":"https://github.com/pvojtechovsky","followers_url":"https://api.github.com/users/pvojtechovsky/followers","following_url":"https://api.github.com/users/pvojtechovsky/following{/other_user}","gists_url":"https://api.github.com/users/pvojtechovsky/gists{/gist_id}","starred_url":"https://api.github.com/users/pvojtechovsky/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/pvojtechovsky/subscriptions","organizations_url":"https://api.github.com/users/pvojtechovsky/orgs","repos_url":"https://api.github.com/users/pvojtechovsky/repos","events_url":"https://api.github.com/users/pvojtechovsky/events{/privacy}","received_events_url":"https://api.github.com/users/pvojtechovsky/received_events","type":"User","site_admin":false},"labels":[],"state":"open","locked":false,"assignee":null,"assignees":[],"milestone":null,"comments":61,"created_at":"2016-12-22T10:04:29Z","updated_at":"2016-12-30T08:25:44Z","closed_at":null,"body":"Main goal: better performance for large queries (no creation of useless intermediate lists)\r\n\r\nRequirements for the new feature:\r\n\r\n1. support of lazy foreach \r\n    * <s>`CtQuery extends Iterator` would an elegant solution  but not possible because a Scanner is not iterable </s>\r\n1. support for chaining of foreach\r\n    * what should be the elements given for the next steps?\r\n1. support for lazy evaluation in map for functions that returns an iterator.\r\n1. reusable queries which will be used with code like `CtQuery query = new CtBaseQueryImpl().map(...).map(...)` reusable over multiple inputs\r\n1. support for sending of results of one step directly to next step, without necessity to build helper lists.\r\n```java\r\ninterface CtQuery { // already exists\r\n  /** Performs an action on each element of the query results.\r\n    * Implemented efficiently for CtScanner based queries */\r\n  CtQuery forEach(CtQueryStep);\r\n}\r\n\r\ninterface CtQueryStep {\r\n  /** \r\n   * evaluates query step and applies mapping of one input element to many output elements.\r\n   * The output elements are `returned` by call of `outputConsumer.accept(outputElement)`, \r\n   * which is called once for each outputElement\r\n   */\r\n   void evaluate(Object input, CtConsumer<Object> outputConsumer);\r\n}\r\n\r\n/**This interface is equivavlent to java 8 Consumer. \r\nWe can remove it after we upgrade to java 8 */\r\ninterface CtConsumer<T> {\r\n void accept(T item);\r\n}\r\n```\r\nThe method `CtQuery#map(CtQueryStep)` is semantically equal to the existing method `CtQuery#map(CtFunction)`. The only difference is the way how result of mapping is delivered to the next query step.\r\n* Implementation of CtFunction - returns result by `return objectBooleanOrList;`. This is optimal for mapping functions which returns 1 or few elements.\r\n* Implementation of CtQueryStep- returns result by `outputConsumer.apply(item)`, which is called for each spoon model element, which has to be returned by this step. This is optimal for mapping functions, which returns many elements.\r\n\r\n--------------------------------------------\r\n\r\nI need a spoon query, which correctly returns all the references to an private or protected class field. It means that query must search for references in correct scope(s).\r\n\r\nThere was an idea how to implement it during development of PR #1018, but then we removed that code for simplicity reasons. \r\n\r\n@monperrus does it makes sense to create a new PR, which will reuse the same ideas again or do you know some better way?"},"comment":{"url":"https://api.github.com/repos/INRIA/spoon/issues/comments/269745232","html_url":"https://github.com/INRIA/spoon/issues/1070#issuecomment-269745232","issue_url":"https://api.github.com/repos/INRIA/spoon/issues/1070","id":269745232,"user":{"login":"pvojtechovsky","id":23107345,"avatar_url":"https://avatars.githubusercontent.com/u/23107345?v=3","gravatar_id":"","url":"https://api.github.com/users/pvojtechovsky","html_url":"https://github.com/pvojtechovsky","followers_url":"https://api.github.com/users/pvojtechovsky/followers","following_url":"https://api.github.com/users/pvojtechovsky/following{/other_user}","gists_url":"https://api.github.com/users/pvojtechovsky/gists{/gist_id}","starred_url":"https://api.github.com/users/pvojtechovsky/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/pvojtechovsky/subscriptions","organizations_url":"https://api.github.com/users/pvojtechovsky/orgs","repos_url":"https://api.github.com/users/pvojtechovsky/repos","events_url":"https://api.github.com/users/pvojtechovsky/events{/privacy}","received_events_url":"https://api.github.com/users/pvojtechovsky/received_events","type":"User","site_admin":false},"created_at":"2016-12-30T08:25:44Z","updated_at":"2016-12-30T08:25:44Z","body":">>>> But there are 2 APIs in query engine. One for element based query - CtQuery and second for reusable query CtBaseQuery.\r\n>>>\r\n>>>I'd prefer to avoid this and have a single API.\r\n>>\r\n>> I guess you prefer one API, because it is simpler for clients right?\r\n>\r\n> Yes\r\n\r\nI am glad that we both want simple API for spoon clients. It is probably unbelievable at first sight, but I think that these 2 simple APIs are simpler/better for clients, then 1 more complex API. \r\n\r\nWhy 2 is simpler then 1?\r\nBecause the only reason, why I designed these 2 APIs is **to make it simple for clients**. There is no other internal reason for 2 APIs.\r\n\r\nYou probably think: If there are 2 APIs then client must choose, which one to use, so it is more complex then 1 API, where this choice is not needed. \r\nBut it is not true in this case, because this decision is done automatically by the context where the query is used. There are two contexts:\r\n\r\n1) the query, which starts on CtElement\r\n```java\r\nanElement.map(...).forEach(...);\r\n//or \r\nList aList = anElement.map(...).list();\r\n```\r\nNote: that in this context client automatically gets `CtQuery` API. In this context there is no reason to confuse client with methods like `evaluate`, `bindTo` or `prepareFor`. Client does not need these methods here at all, therefore **it is simpler for him/her when these methods are not there**.\r\n\r\n2) the reusable query, which is created without initial CtElement\r\n```java\r\nCtBaseQuery query = factory.Query().map(...);\r\n\r\n//... loop for each searched element ...\r\nquery.apply(element, new CtConsumer() {\r\n   void accept(CtElement e) {\r\n      System.out.println(e);\r\n   }\r\n}); \r\n```\r\nNote: that in this context client automatically gets `CtBaseQuery` API. In this context there is no reason to confuse client with methods like `evaluate`, `bindTo` or `prepareFor` followed by `forEach` or `list`. Client has only one simple method `apply`. I have no problem to rename it, if the name is not good. But again **one method is simpler then 2 methods**, which has to be called in correct order, which has to be learned in documentation.\r\n\r\nBaby steps in wrong direction are steps in wrong direction, even when parents love their baby. ;-)"}}
{"actor":{"display_login":"pvojtechovsky"}}