স্কেল সংকলক ডিফল্ট আর্গুমেন্টগুলির সাথে ওভারলোড হওয়া পদ্ধতিগুলি কেন অস্বীকার করে?


148

যদিও এমন বৈধ কেস থাকতে পারে যেখানে এ জাতীয় পদ্ধতির ওভারলোডিংগুলি দ্ব্যর্থহীন হয়ে উঠতে পারে, কেন সংকলক কোডটি বাতিল করবেন না যা সংকলনের সময় বা রান টাইমে দু'বারই অস্পষ্ট নয়?

উদাহরণ:

// This fails:
def foo(a: String)(b: Int = 42) = a + b
def foo(a: Int)   (b: Int = 42) = a + b

// This fails, too. Even if there is no position in the argument list,
// where the types are the same.
def foo(a: Int)   (b: Int = 42) = a + b
def foo(a: String)(b: String = "Foo") = a + b

// This is OK:
def foo(a: String)(b: Int) = a + b
def foo(a: Int)   (b: Int = 42) = a + b    

// Even this is OK.
def foo(a: Int)(b: Int) = a + b
def foo(a: Int)(b: String = "Foo") = a + b

val bar = foo(42)_ // This complains obviously ...

এই বিধিনিষেধগুলি কিছুটা lিলা করা যায় না তার কোনও কারণ আছে কি?

বিশেষত যখন ভারী ওভারলোড হওয়া জাভা কোডটিকে স্কালার ডিফল্ট আর্গুমেন্টে রূপান্তর করা খুব গুরুত্বপূর্ণ এবং স্পেক / সংকলক স্বেচ্ছাসেবক বিধিনিষেধ আরোপ করে এমন একটি স্কালা পদ্ধতি দ্বারা জাভা পদ্ধতি প্রচুর পরিমাণে প্রতিস্থাপনের পরে খুঁজে বের করা ভাল নয়।


18
"স্বেচ্ছাসেবী বিধিনিষেধ" :-)
কাজম্যাগনুস

1
দেখে মনে হচ্ছে আপনি প্রকারের আর্গুমেন্ট ব্যবহার করে সমস্যাটি পেতে পারেন। এটি সংকলন করে:object Test { def a[A](b: Int, c: Int, d: Int = 7): Unit = {}; def a[A](a:String, b: String = ""): Unit = {}; a(2,3,4); a("a");}
ব্যবহারকারী1609012

@ ব্যবহারকারী1609012: আপনার কৌশলটি আমার পক্ষে কার্যকর হয়নি। আমি স্কেলা 2.12.0 এবং স্কেলা 2.11.8 ব্যবহার করে এটি ব্যবহার করে দেখেছি।
ল্যান্ডলকড সার্ফার

4
আইএমএইচও এটি স্কালার অন্যতম শক্তিশালী ব্যথা-পয়েন্ট। আমি যখনই একটি নমনীয় এপিআই সরবরাহ করার চেষ্টা করি তখন আমি প্রায়শই এই সমস্যাটি বিশেষভাবে সহযন্ত্রের বস্তুর প্রয়োগ () প্রয়োগ করার সময় প্রযোজ্য। যদিও আমি কোটলিনের চেয়ে স্ক্যালাকে সামান্য পছন্দ করি, কোটলিনে আপনি এই ধরণের ওভারলোডিং করতে পারেন ...
কিউবিক লেটুস

উত্তর:


113

আমি লুকাশ রায়েজ ( এখানে থেকে ) উদ্ধৃত করতে চাই :

কারণটি হ'ল আমরা উত্পন্ন পদ্ধতিগুলির জন্য একটি নিয়ামবাদী নামকরণ-স্কিম চেয়েছিলাম যা ডিফল্ট যুক্তিগুলি ফিরিয়ে দেয়। যদি লিখি

def f(a: Int = 1)

সংকলক উত্পন্ন

def f$default$1 = 1

যদি একই প্যারামিটার পজিশনে আপনার ডিফল্ট দুটি ওভারলোড থাকে তবে আমাদের আলাদা নামকরণের স্কিম প্রয়োজন। তবে আমরা জেনারেটেড বাইট-কোডটিকে একাধিক সংকলক রানের উপরে স্থিত রাখতে চাই।

ভবিষ্যতের স্কালাল সংস্করণের সমাধান হ'ল নামকরণ স্কিমাতে অ-ডিফল্ট আর্গুমেন্টগুলির (যেমন একটি পদ্ধতির শুরুতে ওভারলোড হওয়া সংস্করণগুলি ছড়িয়ে দেওয়া হয়) এর নাম অন্তর্ভুক্ত করা যেতে পারে , যেমন এই ক্ষেত্রে:

def foo(a: String)(b: Int = 42) = a + b
def foo(a: Int)   (b: Int = 42) = a + b

এটি এমন কিছু হবে:

def foo$String$default$2 = 42
def foo$Int$default$2 = 42

এসআইপি প্রস্তাব লিখতে ইচ্ছুক কেউ ?


2
আমি মনে করি যে এখানে আপনার প্রস্তাবনাটি অনেক অর্থবোধ করে, এবং এটি নির্দিষ্টকরণ / প্রয়োগকরণ সম্পর্কে কী জটিল হবে তা আমি দেখতে পাই না। মূলত, প্যারামিটারের ধরণগুলি ফাংশনের আইডির একটি অংশ। সংকলক বর্তমানে foo (স্ট্রিং) এবং foo (Int) (অর্থাত্, একটি ডিফল্ট ছাড়া ওভারলোডেড পদ্ধতি) দিয়ে কী করবে?
চিহ্নিত করুন

জাভা থেকে স্কালা পদ্ধতিগুলি অ্যাক্সেস করার সময় এগুলি কার্যকরভাবে বাধ্যতামূলক হাঙ্গেরিয়ান নোটেশনটি প্রবর্তন করবে না? দেখে মনে হচ্ছে এটি ইন্টারফেসকে অত্যন্ত ভঙ্গুর করে তুলবে, যখন ফাংশনগুলির প্যারামিটারগুলি টাইপ করার সময় ব্যবহারকারীকে যত্ন নিতে বাধ্য করে।
বিস্ফোরণ_হর্দিজ

এছাড়াও, জটিল ধরনের সম্পর্কে কি? A with B, এই ক্ষেত্রে?
বিস্ফোরণ_হর্দিজ

66

ডিফল্ট আর্গুমেন্টগুলির সাথে ওভারলোডিং রেজোলিউশনের ইন্টারঅ্যাকশনগুলির জন্য একটি পঠনযোগ্য এবং সুনির্দিষ্ট ধারণা পাওয়া খুব কঠিন হবে। অবশ্যই, অনেকগুলি পৃথক ক্ষেত্রে যেমন এখানে উপস্থাপিত হয়েছে, কী হওয়া উচিত তা বলা সহজ। তবে তা যথেষ্ট নয়। আমাদের এমন একটি অনুমানের প্রয়োজন যা সমস্ত সম্ভাব্য কোণার কেসগুলি স্থির করে। ওভারলোডিং রেজোলিউশন নির্দিষ্ট করা ইতিমধ্যে খুব কঠিন। মিশ্রণে ডিফল্ট যুক্তি যুক্ত করা আরও শক্ত করে তুলবে। এজন্যই আমরা দুজনকে আলাদা করতে বেছে নিয়েছি।


4
আপনার উত্তরের জন্য ধন্যবাদ. সম্ভবত যে বিষয়টি আমাকে বিভ্রান্ত করেছিল তা হ'ল মূলত অন্য কোথাও কম্পাইলার কেবল অভিযোগ করে যদি সেখানে কিছুটা অস্পষ্টতা থাকে। তবে এখানে সংকলকটি অভিযোগ করে কারণ এখানে একই ধরণের ঘটনা থাকতে পারে যেখানে অস্পষ্টতা দেখা দিতে পারে। সুতরাং প্রথম ক্ষেত্রে সংকলক কেবলমাত্র যদি প্রমাণিত সমস্যা থাকে তবেই অভিযোগ করে তবে দ্বিতীয় ক্ষেত্রে সংকলক আচরণটি খুব কম সুনির্দিষ্ট হয় এবং "আপাতদৃষ্টিতে বৈধ" কোডের জন্য ত্রুটিগুলি ট্রিগার করে। ন্যূনতম বিস্ময়ের নীতিকে দেখে এটি কিছুটা দুর্ভাগ্যজনক।
সোস

2
"কোনও পাঠযোগ্য এবং সুনির্দিষ্ট স্পেসিফিকেশন পাওয়া খুব কঠিন হবে [...]" এর অর্থ হ'ল যে কেউ যদি একটি ভাল স্পেসিফিকেশন এবং / বা বাস্তবায়ন নিয়ে পদক্ষেপ নেয় তবে বর্তমান পরিস্থিতির উন্নতি হওয়ার সম্ভাবনা রয়েছে? বর্তমান পরিস্থিতি এই প্রোগ্রামটিতে নামে / ডিফল্ট প্যারামিটার ব্যবহারযোগ্যতা বেশ একটু সীমিত ...
SOC

বৈশিষ্টটিতে পরিবর্তন প্রস্তাব করার জন্য একটি প্রক্রিয়া রয়েছে। scala-lang.org/node/233
জেমস আইরি

2
স্কলা তৈরি ওভারলোডিং সম্পর্কে ভ্রান্ত হওয়া এবং দ্বিতীয় শ্রেণির নাগরিক সম্পর্কে আমার কিছু মন্তব্য (লিঙ্কিত উত্তরের নীচে আমার মন্তব্য দেখুন) have আমরা যদি স্কেলায় উদ্দেশ্যমূলকভাবে ওভারলোডিংকে দুর্বল করে চলতে থাকি তবে আমরা নামগুলি দিয়ে টাইপিং প্রতিস্থাপন করছি যা আইএমও একটি প্রতিরোধমূলক দিক।
শেলবি মুর III

10
পাইথন যদি এটি করতে পারে তবে আমি স্কালার পক্ষে পারার কোনও ভাল কারণ দেখতে পাচ্ছি না। জটিলতার পক্ষে যুক্তিটি একটি ভাল: এই বৈশিষ্ট্যটি প্রয়োগ করা ব্যবহারকারীর দৃষ্টিকোণ থেকে স্কেলকে কম জটিল করে তুলবে। অন্যান্য উত্তরগুলি পড়ুন এবং আপনি কেবলমাত্র এমন সমস্যা সমাধানের জন্য লোকেরা খুব জটিল জিনিস উদ্ভাবন করতে দেখবেন যা ব্যবহারকারীর দৃষ্টিকোণ থেকে থাকাও উচিত নয়।
রিচার্ড গমেস 19

12

আমি আপনার প্রশ্নের উত্তর দিতে পারি না, তবে এখানে একটি কার্যকারিতা রয়েছে:

implicit def left2Either[A,B](a:A):Either[A,B] = Left(a)
implicit def right2Either[A,B](b:B):Either[A,B] = Right(b)

def foo(a: Either[Int, String], b: Int = 42) = a match {
  case Left(i) => i + b
  case Right(s) => s + b
}

আপনার যদি দুটি খুব দীর্ঘ আরগের তালিকা থাকে যা কেবলমাত্র একটি আর্গ থেকে পৃথক হয়, তবে এটি সমস্যার জন্য উপযুক্ত হতে পারে ...


1
ঠিক আছে, আমি আমার কোডটি আরও সংক্ষিপ্ত এবং পঠনযোগ্য করার জন্য ডিফল্ট যুক্তিগুলি ব্যবহার করার চেষ্টা করেছি ... আসলে আমি এক ক্ষেত্রে ক্লাসে একটি অন্তর্নিহিত রূপান্তর যুক্ত করেছি যা কেবলমাত্র বিকল্প প্রকারটিকে গ্রহণযোগ্য ধরণের রূপান্তরিত করে না। এটা ঠিক কুৎসিত লাগে। এবং ডিফল্ট আরোগুলি সহ পদ্ধতির কাজ করা উচিত!
সোস

আপনি এই ধরনের ধর্মান্তর সঙ্গে সতর্কতা অবলম্বন করা উচিত যেহেতু তারা সব ব্যবহারের জন্য প্রযোজ্য Eitherএবং ঠিক foo- এই পথ, যখনই কোন Either[A, B]মান অনুরোধ করা হয়, উভয় Aএবং Bগৃহীত হয়। এর পরিবর্তে এমন একটি প্রকারের সংজ্ঞা দেওয়া উচিত যা আপনি কেবল fooএই দিকটিতে যেতে চাইলে ডিফল্ট আর্গুমেন্ট (যেমন এখানে) ফাংশন দ্বারা গ্রহণযোগ্য ; অবশ্যই এটি আরও কম স্পষ্ট হয়ে ওঠে যে এটি কোনও সুবিধাজনক সমাধান কিনা।
ব্লেসরব্লেড

9

আমার জন্য যা কাজ করেছে তা হ'ল ওভারলোডিং পদ্ধতিগুলি (জাভা-স্টাইল) পুনরায় সংজ্ঞা দেওয়া।

def foo(a: Int, b: Int) = a + b
def foo(a: Int, b: String) = a + b
def foo(a: Int) = a + "42"
def foo(a: String) = a + "42"

এটি বর্তমান পরামিতিগুলি অনুসারে আপনি কোন রেজোলিউশন চান তা সংকলকটিকে নিশ্চিত করে।


3

এখানে @ ল্যান্ডইয়ের উত্তরটির একটি সাধারণীকরণ দেওয়া হল:

আপনি কি সত্যিই চান:

def pretty(tree: Tree, showFields: Boolean = false): String = // ...
def pretty(tree: List[Tree], showFields: Boolean = false): String = // ...
def pretty(tree: Option[Tree], showFields: Boolean = false): String = // ...

Workarround

def pretty(input: CanPretty, showFields: Boolean = false): String = {
  input match {
    case TreeCanPretty(tree)       => prettyTree(tree, showFields)
    case ListTreeCanPretty(tree)   => prettyList(tree, showFields)
    case OptionTreeCanPretty(tree) => prettyOption(tree, showFields)
  }
}

sealed trait CanPretty
case class TreeCanPretty(tree: Tree) extends CanPretty
case class ListTreeCanPretty(tree: List[Tree]) extends CanPretty
case class OptionTreeCanPretty(tree: Option[Tree]) extends CanPretty

import scala.language.implicitConversions
implicit def treeCanPretty(tree: Tree): CanPretty = TreeCanPretty(tree)
implicit def listTreeCanPretty(tree: List[Tree]): CanPretty = ListTreeCanPretty(tree)
implicit def optionTreeCanPretty(tree: Option[Tree]): CanPretty = OptionTreeCanPretty(tree)

private def prettyTree(tree: Tree, showFields: Boolean): String = "fun ..."
private def prettyList(tree: List[Tree], showFields: Boolean): String = "fun ..."
private def prettyOption(tree: Option[Tree], showFields: Boolean): String = "fun ..."

1

সম্ভাব্য দৃশ্যের একটি


  def foo(a: Int)(b: Int = 10)(c: String = "10") = a + b + c
  def foo(a: Int)(b: String = "10")(c: Int = 10) = a + b + c

কোনটি কল করতে হবে সে সম্পর্কে সংকলক বিভ্রান্ত হবে। অন্যান্য সম্ভাব্য ঝুঁকি প্রতিরোধে, সংকলকটিতে সর্বাধিক একটি ওভারলোড পদ্ধতিতে ডিফল্ট যুক্তি থাকতে পারে।

শুধু আমার অনুমান :-)


0

আমার উপলব্ধিটি হ'ল ডিফল্ট আর্গুমেন্ট মান সহ সংকলিত শ্রেণিতে নামের সংঘর্ষ হতে পারে। বেশ কয়েকটি থ্রেডে উল্লিখিত এই রেখাগুলির সাথে আমি কিছু দেখেছি।

নামযুক্ত আর্গুমেন্ট স্পেকটি এখানে রয়েছে: http://www.scala-lang.org/sites/default/files/sids/rytz/Mon,%202009-11-09,%2017:29/ নাম-args.pdf

এতে বলা হয়েছে:

 Overloading If there are multiple overloaded alternatives of a method, at most one is
 allowed to specify default arguments.

সুতরাং, আপাতত কোনও হারে, এটি কাজ করছে না।

আপনি জাভাতে যা করতে পারেন তার মতো কিছু করতে পারেন, যেমন:

def foo(a: String)(b: Int) =  a + (if (b > 0) b else 42)
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.