কৌতূহলী নাল-কোয়েলসিং অপারেটর কাস্টম নিহিত রূপান্তর আচরণ


542

দ্রষ্টব্য: এটি রোজলিনে স্থির করা হয়েছে বলে মনে হয়

এই প্রশ্নের উঠে যখন আমার উত্তর লেখার এই এক , যার মধ্যে associativity সম্পর্কে আলোচনা নাল-কোয়ালেসিং অপারেটর

একটি অনুস্মারক হিসাবে, নাল-কোলেসিং অপারেটরের ধারণা হ'ল ফর্মের একটি অভিব্যক্তি

x ?? y

প্রথমে মূল্যায়ন করুন x, তারপরে:

  • মানটি xযদি নাল yহয় তবে মূল্যায়ন করা হয় এবং এটিই অভিব্যক্তির শেষ ফলাফল
  • যদি মানটি xনন-নাল yহয় তবে মূল্যায়ন করা হয় না এবং এর মান হয়xy প্রয়োজনে সংকলন-সময়ের ধরণের রূপান্তর করার পরে প্রকাশের শেষ ফলাফল হয়

এখন সাধারণত কোনও রূপান্তরের প্রয়োজন হয় না, বা এটি কেবলমাত্র একটি প্রবণতা থেকে শুরু করে অ-শনাক্তযোগ্য - সাধারণত প্রকারগুলি একই রকম হয়, বা কেবল (বলুন) int?থেকেint । যাইহোক, আপনি আপনার নিজের অন্তর্নিহিত রূপান্তর অপারেটরগুলি তৈরি করতে পারেন এবং এটি প্রয়োজনীয় যেখানে ব্যবহৃত হয়।

এর সাধারণ মামলার জন্য x ?? y , আমি কোনও বিজোড় আচরণ দেখিনি। যাইহোক, (x ?? y) ?? zআমি কিছু বিভ্রান্তিকর আচরণ দেখতে।

এখানে একটি সংক্ষিপ্ত তবে সম্পূর্ণ পরীক্ষামূলক প্রোগ্রাম - ফলাফলগুলি মন্তব্যে রয়েছে:

using System;

public struct A
{
    public static implicit operator B(A input)
    {
        Console.WriteLine("A to B");
        return new B();
    }

    public static implicit operator C(A input)
    {
        Console.WriteLine("A to C");
        return new C();
    }
}

public struct B
{
    public static implicit operator C(B input)
    {
        Console.WriteLine("B to C");
        return new C();
    }
}

public struct C {}

class Test
{
    static void Main()
    {
        A? x = new A();
        B? y = new B();
        C? z = new C();
        C zNotNull = new C();

        Console.WriteLine("First case");
        // This prints
        // A to B
        // A to B
        // B to C
        C? first = (x ?? y) ?? z;

        Console.WriteLine("Second case");
        // This prints
        // A to B
        // B to C
        var tmp = x ?? y;
        C? second = tmp ?? z;

        Console.WriteLine("Third case");
        // This prints
        // A to B
        // B to C
        C? third = (x ?? y) ?? zNotNull;
    }
}

সুতরাং আমাদের তিনটি কাস্টম মান প্রকার আছে A,B এবং C, সি বি, একটি সি, এবং বি A থেকে ধর্মান্তর সঙ্গে

আমি দ্বিতীয় কেস এবং তৃতীয় কেস উভয়ই বুঝতে পারি ... তবে কেন প্রথম ক্ষেত্রে অতিরিক্ত A থেকে B রূপান্তর হয়? বিশেষত, আমি চাই সত্যিই প্রথম কেস এবং দ্বিতীয় কেসটি একই জিনিস হওয়ার প্রত্যাশা - এটি কেবল একটি স্থানীয় ভেরিয়েবলের মধ্যে একটি এক্সপ্রেশন বের করছে, সর্বোপরি।

কি চলছে তাতে কোন গ্রহণকারী? সি # কম্পাইলারের কথাটি শুনে আমি "বাগ" কাঁদতে চরম সংবেদনশীল, তবে কী হচ্ছে তা নিয়ে আমি স্তিমিত হয়েছি ...

সম্পাদনা: ঠিক আছে, এখানে যা চলছে তার একটি পূর্ববর্তী উদাহরণ, কনফিগারারের উত্তরকে ধন্যবাদ, যা আমাকে এটি একটি বাগ বলে মনে করার আরও কারণ দেয়। সম্পাদনা: নমুনার জন্য এখন পর্যন্ত দুটি নাল-কোলেসিং অপারেটর প্রয়োজন নেই ...

using System;

public struct A
{
    public static implicit operator int(A input)
    {
        Console.WriteLine("A to int");
        return 10;
    }
}

class Test
{
    static A? Foo()
    {
        Console.WriteLine("Foo() called");
        return new A();
    }

    static void Main()
    {
        int? y = 10;

        int? result = Foo() ?? y;
    }
}

এর ফলাফল:

Foo() called
Foo() called
A to int

Foo()এখানে দু'বার কল করা সত্যটি আমার কাছে বিস্ময়কর - আমি দু'বার অভিব্যক্তির মূল্যায়ন করার কোনও কারণ দেখতে পাচ্ছি না ।


32
আমি বাজি
ধরলাম

57
আরও খারাপ কিছু দেখতে চান? সব অন্তর্নিহিত ধর্মান্তর সঙ্গে এই লাইন ব্যবহার করার চেষ্টা করুন: C? first = ((B?)(((B?)x) ?? ((B?)y))) ?? ((C?)z);। আপনি পাবেন:Internal Compiler Error: likely culprit is 'CODEGEN'
কনফিগারকারী

5
এছাড়াও নোট করুন যে একই কোডটি সংকলন করতে লিনক এক্সপ্রেশন ব্যবহার করার সময় ঘটে না।
Configurator

8
@ পিটার সম্ভাবনাময় নিদর্শন, তবে এর পক্ষে প্রশংসনীয়(("working value" ?? "user default") ?? "system default")
ফ্যাক্টর মিস্টিক

23
@ হ্যাঁ 123: যখন এটি কেবল রূপান্তরটির সাথে মোকাবিলা করছিল তখন আমি পুরোপুরি বিশ্বাস করি না। এটি কোনও পদ্ধতির দু'বার সম্পাদন করে দেখলে এটি স্পষ্ট হয়ে যায় এটি একটি বাগ was আপনি এমন কিছু আচরণ দেখে অবাক হবেন যা ভুল দেখাচ্ছে তবে বাস্তবে সম্পূর্ণ সঠিক। সি # টিম আমার চেয়ে বুদ্ধিমান - আমি ধরে নিই যে আমি বোকা হয়েছি যতক্ষণ না আমি প্রমাণ করেছি যে কিছু তাদের দোষ is
জন স্কিটি

উত্তর:


418

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

সঠিকভাবে জিনিসগুলি কোথায় ভুল হয়েছে তা আমি এখনও শনাক্ত করতে পারি নি, তবে সংকলনের "nullable lowing" পর্যায়ে কিছুটা সময় - প্রাথমিক বিশ্লেষণের পরে কিন্তু কোড তৈরির আগে - আমরা অভিব্যক্তি হ্রাস করি

result = Foo() ?? y;

উপরের উদাহরণ থেকে নৈতিক সমতুল্য:

A? temp = Foo();
result = temp.HasValue ? 
    new int?(A.op_implicit(Foo().Value)) : 
    y;

স্পষ্টতই এটি ভুল; সঠিক হ্রাস হয়

result = temp.HasValue ? 
    new int?(A.op_implicit(temp.Value)) : 
    y;

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

result = Foo() ?? y;

হিসাবে একই

A? temp = Foo();
result = temp.HasValue ? 
    (int?) temp : 
    y;

এবং তারপরে আমরা এটি বলতে পারি

conversionResult = (int?) temp 

হিসাবে একই

A? temp2 = temp;
conversionResult = temp2.HasValue ? 
    new int?(op_Implicit(temp2.Value)) : 
    (int?) null

তবে অপ্টিমাইজার পদক্ষেপে বলতে পারেন এবং "হোয়া, এক মিনিট অপেক্ষা করুন, আমরা ইতিমধ্যে পরীক্ষা করে দেখলাম যে অস্থায়ীতা বাতিল নয়; কেবলমাত্র আমরা একটি লিফট রূপান্তর অপারেটরকে ডাকছি বলে" এটি দ্বিতীয়বার নাল পরীক্ষা করার দরকার নেই "। আমরা তাদের এটিকে কেবলমাত্র উন্নত করতে চাই

new int?(op_Implicit(temp2.Value)) 

আমার অনুমান যে আমরা কোথাও আসলে ক্যাশে করা হয় যে অপ্টিমাইজ ফর্ম (int?)Foo()হয় new int?(op_implicit(Foo().Value))কিন্তু যে আসলে অপ্টিমাইজ ফর্ম আমরা চাই না; আমরা ফু এর অপ্টিমাইজড ফর্মটি চাই - (অস্থায়ী-এবং-পরে-রূপান্তরিত)।

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

আমরা সি # 3.0 এ অবিচ্ছিন্ন পুনর্নির্মাণের পাসের অনেকগুলি পুনর্গঠন করেছি। বাগটি সি # 3.0 এবং 4.0 এ পুনরুত্পাদন করে তবে সি # 2.0 তে নয়, এর অর্থ সম্ভবত বাগটি আমার খারাপ ছিল। দুঃখিত!

আমি ডাটাবেসে একটি ত্রুটি প্রবেশ করিয়ে নেব এবং আমরা দেখতে পাব আমরা ভাষার ভবিষ্যতের সংস্করণে এটি ঠিক করতে পারি কিনা। আপনার বিশ্লেষণের জন্য সবাইকে আবার ধন্যবাদ; এটা খুব সহায়ক ছিল!

আপডেট: আমি রোজলিনের জন্য স্ক্র্যাচ থেকে নালাম অপটিমাইজারটি আবার লিখেছি; এটি এখন আরও ভাল কাজ করে এবং এই ধরণের অদ্ভুত ত্রুটিগুলি এড়িয়ে চলে। রোজলিনে অপ্টিমাইজার কীভাবে কাজ করে সে সম্পর্কে কিছু ধারণার জন্য, এখানে আমার শুরু হওয়া নিবন্ধগুলি দেখুন: https://ericlippert.com/2012/12/20/nullable-micro-optimizations-part-one/


1
@Eric আমি ভাবছি যদি এই ব্যাখ্যা করবে: connect.microsoft.com/VisualStudio/feedback/details/642227
MarkPflug

12
এখন আমার কাছে রোজলিনের শেষ ব্যবহারকারী পূর্বরূপ রয়েছে, আমি নিশ্চিত করতে পারি যে এটি ঠিক আছে fixed (যদিও এটি স্থানীয় সি # 5 সংকলনে এখনও উপস্থিত রয়েছে))
জন স্কিটি

84

এটি অবশ্যই একটি বাগ।

public class Program {
    static A? X() {
        Console.WriteLine("X()");
        return new A();
    }
    static B? Y() {
        Console.WriteLine("Y()");
        return new B();
    }
    static C? Z() {
        Console.WriteLine("Z()");
        return new C();
    }

    public static void Main() {
        C? test = (X() ?? Y()) ?? Z();
    }
}

এই কোডটি আউটপুট দেবে:

X()
X()
A to B (0)
X()
X()
A to B (0)
B to C (0)

এটি আমাকে ভাবতে বাধ্য করেছে যে প্রতিটি ??সম্মিলিত প্রকাশের প্রথম অংশটি দুবার মূল্যায়ন করা হয়। এই কোডটি এটি প্রমাণ করেছে:

B? test= (X() ?? Y());

আউটপুট:

X()
X()
A to B (0)

এটি তখনই ঘটবে বলে মনে হয় যখন অভিব্যক্তিটির জন্য দুটি অপ্রয়োজনীয় ধরণের মধ্যে রূপান্তর প্রয়োজন; আমি পক্ষের মধ্যে একটি স্ট্রিং হয়ে বিভিন্ন বিচ্যুতি চেষ্টা করেছি এবং তাদের মধ্যে কেউই এই আচরণের কারণ হয়নি।


11
বাহ - অভিব্যক্তিটির দুবার মূল্যায়ন করা সত্যিই খুব ভুল বলে মনে হচ্ছে। ভাল বিক্ষোভ.
জন স্কিটি

উত্সটিতে আপনার কাছে কেবল একটি পদ্ধতি কল রয়েছে কিনা তা দেখতে কিছুটা সহজ - তবে এটি এখনও এটি খুব স্পষ্টভাবে প্রদর্শন করে।
জন স্কিটি

2
আমি আমার প্রশ্নের সাথে এই "ডাবল মূল্যায়ন" এর সামান্য সরল উদাহরণ যুক্ত করেছি।
জন স্কিটি

8
আপনার সমস্ত পদ্ধতি কি "এক্স ()" আউটপুট দেওয়ার কথা? কনসোলটিতে আসলে কোন পদ্ধতিটি আউটপুট দিচ্ছে তা বলা কিছুটা কঠিন করে তোলে।
jeffora

2
এটি X() ?? Y()অভ্যন্তরীণভাবে প্রসারিত বলে মনে হচ্ছে X() != null ? X() : Y(), সুতরাং কেন এটি দুটিবার মূল্যায়ন করা হবে।
কোল জনসন

54

আপনি যদি বাম-গোষ্ঠীযুক্ত ক্ষেত্রেটির জন্য উত্পন্ন কোডটি একবার দেখে থাকেন তবে এটি আসলে ( csc /optimize-) এর মতো কিছু করে :

C? first;
A? atemp = a;
B? btemp = (atemp.HasValue ? new B?(a.Value) : b);
if (btemp.HasValue)
{
    first = new C?((atemp.HasValue ? new B?(a.Value) : b).Value);
}

অপরকে খুঁজে পেতে, আপনি যদি ব্যবহার first এটি উভয় একটি শর্টকাট তৈরি করব aএবং bনাল এবং বিনিময়ে হয় c। তবুও যদি aবা bঅ-শূন্য হয় তবে কোনটি শূন্য হয় বা ফিরে আসার আগে aতা অন্তর্নিহিত রূপান্তরের অংশ হিসাবে পুনরায় মূল্যায়ন করে ।Bab

সি # 4.0 স্পেসিফিকেশন থেকে, §6.1.4:

  • যদি অযোগ্য রূপান্তরটি থেকে S?থাকে T?:
    • যদি উত্সের মান হয় null( HasValueসম্পত্তি হয় false) তবে ফলাফলটি nullধরণের মান T?
    • অন্যথায়, রূপান্তর থেকে একটি unwrapping যেমন মূল্যায়ন করা হয় S?থেকে S, থেকে অন্তর্নিহিত রূপান্তর দ্বারা অনুসরণ Sকরতে T, থেকে একটি মোড়ানো (§4.1.10) দ্বারা অনুসরণ Tকরতে T?

এটি দ্বিতীয় আন-র্যাপিং-মোড়ক সংমিশ্রণের ব্যাখ্যা করতে উপস্থিত হয়।


সি # ২০০৮ এবং ২০১০ সংকলকটি খুব অনুরূপ কোড তৈরি করে, তবে এটি সি # ২০০২ সংকলক (8.00.50727.4927) থেকে প্রাপ্ত একটি রিগ্রেশনের মতো দেখাচ্ছে যা উপরের জন্য নিম্নলিখিত কোডটি উত্পন্ন করে:

A? a = x;
B? b = a.HasValue ? new B?(a.GetValueOrDefault()) : y;
C? first = b.HasValue ? new C?(b.GetValueOrDefault()) : z;

আমি ভাবছি যদি টাইপ ইনফারেন্স সিস্টেমকে দেওয়া অতিরিক্ত যাদুটির কারণে এটি না হয় ?


+1, তবে আমি মনে করি না যে এটি কেন সত্যই ব্যাখ্যা করে যে কেন দুটি বার রূপান্তর হয়। এটি কেবলমাত্র একবারের ভাবের মূল্যায়ন করা উচিত, আইএমও।
জন স্কিটি

@ জোন: আমি চারপাশে খেলছি এবং খুঁজে পেয়েছি (@ কনফিগ্রেটর যেমন করেছিলেন) যে কোনও এক্সপ্রেশন ট্রিতে কাজ করার সময় এটি প্রত্যাশার মতো কাজ করে। এটি আমার পোস্টে যুক্ত করার জন্য অভিব্যক্তিগুলি পরিষ্কার করার কাজ করছে। আমাকে তখন পোস্ট করতে হবে যে এটি একটি "বাগ"।
ব্যবহারকারী 7116

@ জোন: ঠিক আছে এক্সপ্রেশন ট্রি ব্যবহার করার সময় এটি (x ?? y) ?? zনেস্টেড ল্যাম্বডাসে পরিণত হয়, যা দ্বিগুণ মূল্যায়ন ছাড়াই ক্রম মূল্যায়ন নিশ্চিত করে। এটি স্পষ্টতই সি # 4.0 সংকলক দ্বারা গৃহীত পদ্ধতির নয়। আমি যা বলতে পারি সেগুলি থেকে বিভাগ 6.1.4 খুব নির্দিষ্টভাবে এই নির্দিষ্ট কোডের পথে কঠোরভাবে পৌঁছেছে এবং দ্বিগুণ মূল্যায়নের ফলে টেম্পোরারিগুলিকে আলাদা করা হয় না।
ব্যবহারকারী 7116

16

প্রকৃতপক্ষে, আমি এটিকে এখন একটি বাগ বলব, আরও পরিষ্কার উদাহরণ সহ। এটি এখনও ধারণ করে, তবে ডাবল-মূল্যায়ন অবশ্যই ভাল নয়।

মনে হয় A ?? Bযেমন বাস্তবায়ন করা হয়েছে A.HasValue ? A : B। এই ক্ষেত্রে, প্রচুর ingালাইও রয়েছে (টার্নারি ?:অপারেটরের জন্য নিয়মিত কাস্টিং অনুসরণ করে )। তবে যদি আপনি এই সমস্ত কিছু উপেক্ষা করেন, তবে এটি কীভাবে এটি প্রয়োগ করা হয়েছে তার উপর ভিত্তি করে এটি অর্থবোধ করে:

  1. A ?? B প্রসারিত হয় A.HasValue ? A : B
  2. Aআমাদের x ?? y। প্রসারিত করুনx.HasValue : x ? y
  3. এ -> এর সমস্ত উপস্থিতি প্রতিস্থাপন করুন (x.HasValue : x ? y).HasValue ? (x.HasValue : x ? y) : B

এখানে আপনি দেখতে পাবেন যে x.HasValueএটি দুটিবার পরীক্ষা করা হয়েছে, এবং যদিx ?? y কাস্টিংয়ের প্রয়োজন হয়x দুবার কাস্ট করা হবে।

আমি কীভাবে এটি একটি নিদর্শন হিসাবে এটি নিচে রাখবেন ?? সংকলক বাগের পরিবর্তে বাস্তবায়িত হয় তার । টেক-অ্যাও: পার্শ্ব প্রতিক্রিয়াযুক্ত অন্তর্ভুক্ত কাস্টিং অপারেটরগুলি তৈরি করবেন না।

এটি কীভাবে ??বাস্তবায়ন করা হয় তার চারপাশে ঘূর্ণনকারী একটি সংকলক বাগ বলে মনে হচ্ছে । টেক-অ্যাওয়ে: পার্শ্ব-প্রতিক্রিয়া সহ বাসা বাঁধে না।


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

@ জন আমি সম্মতি জানাই যে এটিও হতে পারে - তবে আমি এটিকে ক্লিয়ার কাট বলব না। ভাল, আসলে, আমি দেখতে পাচ্ছি যে A() ? A() : B()সম্ভবত A()দুবার মূল্যায়ন করবে , তবে A() ?? B()এত বেশি নয়। এবং যেহেতু এটি কেবল ingালাইয়ের ক্ষেত্রে ঘটে ... হুম .. আমি কেবল নিজেকে ভেবে ভেবেছি এটি অবশ্যই সঠিকভাবে আচরণ করছে না।
ফিলিপ রিয়েক

10

আপনি আমার প্রশ্ন ইতিহাস থেকে যেমন দেখতে পাচ্ছেন তেমন আমি কোনও সি # বিশেষজ্ঞ নই, তবে, আমি এটি চেষ্টা করে দেখেছি এবং এটি একটি বাগ বলে মনে করি .... তবে নবাগত হিসাবে, আমাকে বলতে হবে যে আমি যাচ্ছি কিছুই বুঝতে পারছি না এখানে এখানে তাই আমি আমার উত্তর মুছে ফেলব যদি আমি পথ ছাড়ি।

আমি এই এসেছি bug আপনার প্রোগ্রামটির একটি ভিন্ন সংস্করণ তৈরি করে সিদ্ধান্তে পৌঁছেছি যা একই দৃশ্যের সাথে সম্পর্কিত তবে খুব কম জটিল।

আমি ব্যাকিং স্টোর সহ তিনটি নাল পূর্ণসংখ্যা বৈশিষ্ট্য ব্যবহার করছি। আমি প্রতিটি 4 সেট এবং তারপর চালানোint? something2 = (A ?? B) ?? C;

( এখানে সম্পূর্ণ কোড )

এটি কেবল এ পড়ছে এবং অন্য কিছুই নয়।

আমার কাছে দেওয়া এই বক্তব্যটি আমার মতো হওয়া উচিত:

  1. বন্ধনীতে শুরু করুন, এ দেখুন, এ ফিরে আসুন এবং এ শূন্য না হলে শেষ করুন।
  2. যদি এ শূন্য হয়, খকে মূল্যায়ন করুন, বি শূন্য না হলে শেষ করুন
  3. A এবং B যদি নাল হয় তবে সি এর মূল্যায়ন করুন

সুতরাং, যেহেতু এ শূন্য নয়, এটি কেবল এ এর ​​দিকে দেখায় এবং শেষ হয়।

আপনার উদাহরণে, প্রথম কেসটিতে ব্রেকআপপয়েন্ট স্থাপন করে দেখা যায় যে এক্স, ওয়াই এবং জেড সবই নাল নয় এবং তাই আমি তাদের কাছে আমার কম জটিল উদাহরণের মতো আচরণ করা আশা করব .... তবে আমি ভয় করি যে আমি খুব বেশি একটি সি # নবাগত এবং এই প্রশ্নের বিন্দুটি পুরোপুরি মিস করেছেন!


5
জনের উদাহরণটি কিছুটা অস্পষ্ট কোণার ক্ষেত্রে যেটি তিনি একটি নলাবদ্ধ স্ট্রাক্ট ব্যবহার করছেন (একটি মান-ধরণের যা কোনও বিল্ট-ইন-এর মতো "সদৃশ" int)। তিনি একাধিক অন্তর্নিহিত ধরণের রূপান্তর সরবরাহ করে কেসটিকে আরও অস্পষ্ট কোণে ঠেলে দেন। এর বিপরীতে পরীক্ষা করার সময় তথ্যের ধরণের পরিবর্তন করতে সংকলকটির প্রয়োজন null। এই অন্তর্নিহিত ধরণের রূপান্তরগুলির কারণে তার উদাহরণটি আপনার থেকে আলাদা।
user7116
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.